From d5c9375f0f879b2515ae891414b577d875b97681 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 8 Mar 2025 22:04:05 +0330 Subject: [PATCH] last ... --- .../Classes/x-saherelm.base.class.mq5 | 101 + .../Classes/x-saherelm.x-account.class.mq5 | 398 + .../Classes/x-saherelm.x-alert.class.mq5 | 1580 +++ .../Classes/x-saherelm.x-app-dialog.class.mq5 | 275 + .../x-saherelm.x-bar.analyser.class.ex5 | Bin 0 -> 8044 bytes .../x-saherelm.x-bar.analyser.class.mq5 | 6043 +++++++++ .../Classes/x-saherelm.x-cobject.class.mq5 | 3878 ++++++ .../Classes/x-saherelm.x-expert.class.mq5 | 967 ++ .../Classes/x-saherelm.x-helper.class.mq5 | 151 + .../Classes/x-saherelm.x-http.class.mq5 | 373 + .../Classes/x-saherelm.x-md5.class.mq5 | 445 + .../Classes/x-saherelm.x-poi.class.ex5 | Bin 0 -> 8328 bytes .../Classes/x-saherelm.x-poi.class.mq5 | 3334 +++++ .../Classes/x-saherelm.x-poi.drawer.class.ex5 | Bin 0 -> 15212 bytes .../Classes/x-saherelm.x-poi.drawer.class.mq5 | 4922 +++++++ .../Classes/x-saherelm.x-trade.class.mq5 | 3934 ++++++ BKPS/14031218/Documents/BKP/1.ind.ai.mq5 | 196 + BKPS/14031218/Documents/BKP/1.mq5 | 10874 +++++++++++++++ BKPS/14031218/Documents/BKP/Test.mq5 | 243 + BKPS/14031218/Documents/BKP/smc.ea.ex5 | Bin 0 -> 38680 bytes BKPS/14031218/Documents/BKP/smc.ea.mq5 | 418 + BKPS/14031218/Documents/BKP/testob.mq5 | 275 + .../BKP/x-121.smc.xwz.signal.class copy 2.mq5 | 2295 ++++ .../BKP/x-121.smc.xwz.signal.class copy.mq5 | 2124 +++ .../BKP/x-121.smc.xwz.signal.class.mq5 | 3960 ++++++ .../BKP/x-121.smc.xwz.signal.lib copy 2.mq5 | 3189 +++++ .../BKP/x-121.smc.xwz.signal.lib copy.mq5 | 4871 +++++++ .../BKP/x-121.smc.xwz.signal.lib.mq5 | 1582 +++ .../Documents/BKP/x-saherelm.x-poi.class.mq5 | 4218 ++++++ .../Documents/BKP/x-saherelm.x121.xwz.mq5 | 3438 +++++ .../Documents/BKP/x-saherelm.xobfvg.lib.mq5 | 1897 +++ .../Diagrams/Position Protection.drawio | 279 + .../Documents/JsModules/x-color.tools.js | 506 + .../Documents/JsModules/x-file.tools.js | 887 ++ .../Documents/JsModules/x-shell.tools.js | 219 + .../JsModules/x-type-detector.tools.js | 268 + .../Documents/JsModules/x-value.tools.js | 1528 +++ .../Temlates/x-saherelm.x-ea.template.ea.mq5 | 542 + .../Temlates/x-saherelm.x-panel.ea.mq5 | 575 + BKPS/14031218/Experts/Advisors/ExpertMACD.mq5 | 168 + BKPS/14031218/Experts/Advisors/ExpertMAMA.mq5 | 175 + .../Experts/Advisors/ExpertMAPSAR.mq5 | 171 + .../Advisors/ExpertMAPSARSizeOptimized.mq5 | 176 + .../Examples/ChartInChart/ChartInChart.mq5 | Bin 0 -> 30544 bytes .../Experts/Examples/Controls/Controls.mq5 | 45 + .../Examples/Controls/ControlsDialog.mqh | 427 + .../Correlation Matrix 3D.mq5 | Bin 0 -> 77280 bytes .../Correlation Matrix 3D.mqproj | Bin 0 -> 8302 bytes .../Experts/Examples/MACD/MACD Sample.mq5 | 451 + .../Examples/Math 3D Morpher/Functions.mqh | 372 + .../Math 3D Morpher/Math 3D Morpher.mq5 | Bin 0 -> 35776 bytes .../Math 3D Morpher/Math 3D Morpher.mqproj | Bin 0 -> 16042 bytes .../Math 3D Morpher/Textures/checker.bmp | Bin 0 -> 196662 bytes .../Experts/Examples/Math 3D/Functions.mqh | Bin 0 -> 16008 bytes .../Experts/Examples/Math 3D/Math 3D.ico | Bin 0 -> 16958 bytes .../Experts/Examples/Math 3D/Math 3D.mq5 | Bin 0 -> 6986 bytes .../Experts/Examples/Math 3D/Math 3D.mqproj | Bin 0 -> 6042 bytes .../Examples/Math 3D/Sets/Chomolungma.set | Bin 0 -> 684 bytes .../Examples/Math 3D/Sets/ClimberDream.set | Bin 0 -> 696 bytes .../Examples/Math 3D/Sets/DoubleScrew.set | Bin 0 -> 684 bytes .../Experts/Examples/Math 3D/Sets/Granite.set | Bin 0 -> 684 bytes .../Examples/Math 3D/Sets/Hedgehog.set | Bin 0 -> 692 bytes .../Experts/Examples/Math 3D/Sets/Hill.set | Bin 0 -> 688 bytes .../Examples/Math 3D/Sets/Josephine.set | Bin 0 -> 688 bytes .../Math 3D/Sets/MultyExtremalScrew.set | Bin 0 -> 684 bytes .../Experts/Examples/Math 3D/Sets/Screw.set | Bin 0 -> 684 bytes .../Experts/Examples/Math 3D/Sets/Sink.set | Bin 0 -> 686 bytes .../Experts/Examples/Math 3D/Sets/Skin.set | Bin 0 -> 686 bytes .../Examples/Math 3D/Sets/Trapfall.set | Bin 0 -> 686 bytes .../Moving Average/Moving Average.mq5 | 233 + .../BlackCrows WhiteSoldiers CCI.mq5 | 657 + .../BlackCrows WhiteSoldiers MFI.mq5 | 657 + .../BlackCrows WhiteSoldiers RSI.mq5 | 657 + .../BlackCrows WhiteSoldiers Stoch.mq5 | 661 + .../BullishBearish Engulfing CCI.mq5 | 682 + .../BullishBearish Engulfing MFI.mq5 | 682 + .../BullishBearish Engulfing RSI.mq5 | 682 + .../BullishBearish Engulfing Stoch.mq5 | 688 + .../Free Robots/BullishBearish Harami CCI.mq5 | 682 + .../Free Robots/BullishBearish Harami MFI.mq5 | 682 + .../Free Robots/BullishBearish Harami RSI.mq5 | 682 + .../BullishBearish Harami Stoch.mq5 | 685 + .../BullishBearish MeetingLines CCI.mq5 | 654 + .../BullishBearish MeetingLines MFI.mq5 | 652 + .../BullishBearish MeetingLines RSI.mq5 | 653 + .../BullishBearish MeetingLines Stoch.mq5 | 662 + .../DarkCloud PiercingLine CCI.mq5 | 682 + .../DarkCloud PiercingLine MFI.mq5 | 681 + .../DarkCloud PiercingLine RSI.mq5 | 683 + .../DarkCloud PiercingLine Stoch.mq5 | 687 + .../Free Robots/HangingMan Hammer CCI.mq5 | 679 + .../Free Robots/HangingMan Hammer MFI.mq5 | 679 + .../Free Robots/HangingMan Hammer RSI.mq5 | 677 + .../Free Robots/HangingMan Hammer Stoch.mq5 | 683 + .../MorningEvening StarDoji CCI.mq5 | 685 + .../MorningEvening StarDoji MFI.mq5 | 686 + .../MorningEvening StarDoji RSI.mq5 | 686 + .../MorningEvening StarDoji Stoch.mq5 | 691 + .../Experts/x-saherelm.x-121.smc.ea.ex5 | Bin 0 -> 1450086 bytes .../Experts/x-saherelm.x-121.smc.ea.mq5 | 464 + .../Helpers/x-saherelm.x121.helper.mq5 | 4464 +++++++ .../Helpers/x-saherelm.x121.x3ma.helper.mq5 | 1339 ++ .../Helpers/x-saherelm.x121.xatr.helper.mq5 | 1273 ++ .../Helpers/x-saherelm.x121.xcc.helper.mq5 | 252 + .../Helpers/x-saherelm.x121.xche.helper.mq5 | 1387 ++ .../Helpers/x-saherelm.x121.xct.helper.mq5 | 234 + .../Helpers/x-saherelm.x121.xdon.helper.mq5 | 1408 ++ .../Helpers/x-saherelm.x121.xhk.helper.mq5 | 1524 +++ .../Helpers/x-saherelm.x121.xpv.helper.mq5 | 2551 ++++ .../Helpers/x-saherelm.x121.xstr.helper.mq5 | 1112 ++ .../Helpers/x-saherelm.x121.xtrend.helper.mq5 | 1279 ++ .../Helpers/x-saherelm.x121.xvwap.helper.mq5 | 1508 +++ .../Indicators/x-saherelm.x121.x3ma.ex5 | Bin 0 -> 15752 bytes .../Indicators/x-saherelm.x121.x3ma.mq5 | 658 + .../Indicators/x-saherelm.x121.xatr.ex5 | Bin 0 -> 20756 bytes .../Indicators/x-saherelm.x121.xatr.mq5 | 648 + .../Indicators/x-saherelm.x121.xcc.ex5 | Bin 0 -> 13154 bytes .../Indicators/x-saherelm.x121.xcc.mq5 | 437 + .../Indicators/x-saherelm.x121.xche.ex5 | Bin 0 -> 19300 bytes .../Indicators/x-saherelm.x121.xche.mq5 | 624 + .../Indicators/x-saherelm.x121.xct.ex5 | Bin 0 -> 16810 bytes .../Indicators/x-saherelm.x121.xct.mq5 | 262 + .../Indicators/x-saherelm.x121.xdon.ex5 | Bin 0 -> 15592 bytes .../Indicators/x-saherelm.x121.xdon.mq5 | 692 + .../Indicators/x-saherelm.x121.xhk.ex5 | Bin 0 -> 17042 bytes .../Indicators/x-saherelm.x121.xhk.mq5 | 616 + .../Indicators/x-saherelm.x121.xpv.ex5 | Bin 0 -> 43024 bytes .../Indicators/x-saherelm.x121.xpv.mq5 | 1074 ++ .../Indicators/x-saherelm.x121.xstr.ex5 | Bin 0 -> 15236 bytes .../Indicators/x-saherelm.x121.xstr.mq5 | 636 + .../Indicators/x-saherelm.x121.xtrend.ex5 | Bin 0 -> 19292 bytes .../Indicators/x-saherelm.x121.xtrend.mq5 | 700 + .../Indicators/x-saherelm.x121.xvwap.ex5 | Bin 0 -> 16010 bytes .../Indicators/x-saherelm.x121.xvwap.mq5 | 711 + .../Indicators/x-saherelm.x121.xwz.ex5 | Bin 0 -> 113410 bytes .../Indicators/x-saherelm.x121.xwz.mq5 | 2780 ++++ .../Libraries/x-saherelm.common.lib.ex5 | Bin 0 -> 5520 bytes .../Libraries/x-saherelm.common.lib.mq5 | 10893 ++++++++++++++++ .../Libraries/x-saherelm.draw.lib.mq5 | 2626 ++++ .../x-saherelm.x-poi.extensions.lib.ex5 | Bin 0 -> 7894 bytes .../x-saherelm.x-poi.extensions.lib.mq5 | 3113 +++++ .../Libraries/x-saherelm.x-poi.lib.ex5 | Bin 0 -> 7792 bytes .../Libraries/x-saherelm.x-poi.lib.mq5 | 5365 ++++++++ .../Libraries/x-saherelm.x-poi.state.lib.ex5 | Bin 0 -> 7804 bytes .../Libraries/x-saherelm.x-poi.state.lib.mq5 | 4523 +++++++ .../Libraries/x-saherelm.x-trade.lib.ex5 | Bin 0 -> 11796 bytes .../Libraries/x-saherelm.x-trade.lib.mq5 | 6199 +++++++++ .../Classes/x-121.smc.base.strategy.class.mq5 | 650 + .../Classes/x-121.smc.cobjects.class.mq5 | 35 + .../Classes/x-121.smc.ea.panel.class.mq5 | 63 + .../x-121.smc.market.cycle.helper.class.ex5 | Bin 0 -> 16866 bytes .../x-121.smc.market.cycle.helper.class.mq5 | 1082 ++ .../x-121.smc.x-tradehandler.class.mq5 | 4400 +++++++ .../Experts/x-121.smc.expert.class.mq5 | 2479 ++++ .../Libraries/x-121.smc.guard.lib.ex5 | Bin 0 -> 17330 bytes .../Libraries/x-121.smc.guard.lib.mq5 | 970 ++ .../X121SMCEA/Libraries/x-121.smc.lib.ex5 | Bin 0 -> 16286 bytes .../X121SMCEA/Libraries/x-121.smc.lib.mq5 | 737 ++ .../Signals/x-121.smc.xwz.signal.class.ex5 | Bin 0 -> 16196 bytes .../Signals/x-121.smc.xwz.signal.class.mq5 | 1765 +++ .../Signals/x-121.smc.xwz.signal.lib.ex5 | Bin 0 -> 17958 bytes .../Signals/x-121.smc.xwz.signal.lib.mq5 | 3034 +++++ .../Strategy/x-121.smc.strategy.class.ex5 | Bin 0 -> 18960 bytes .../Strategy/x-121.smc.strategy.class.mq5 | 1064 ++ 164 files changed, 169551 insertions(+) create mode 100644 BKPS/14031218/Classes/x-saherelm.base.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-account.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-alert.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-app-dialog.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-bar.analyser.class.ex5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-bar.analyser.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-cobject.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-expert.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-helper.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-http.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-md5.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-poi.class.ex5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-poi.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.ex5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.mq5 create mode 100644 BKPS/14031218/Classes/x-saherelm.x-trade.class.mq5 create mode 100644 BKPS/14031218/Documents/BKP/1.ind.ai.mq5 create mode 100644 BKPS/14031218/Documents/BKP/1.mq5 create mode 100644 BKPS/14031218/Documents/BKP/Test.mq5 create mode 100644 BKPS/14031218/Documents/BKP/smc.ea.ex5 create mode 100644 BKPS/14031218/Documents/BKP/smc.ea.mq5 create mode 100644 BKPS/14031218/Documents/BKP/testob.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy 2.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy 2.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-saherelm.x-poi.class.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-saherelm.x121.xwz.mq5 create mode 100644 BKPS/14031218/Documents/BKP/x-saherelm.xobfvg.lib.mq5 create mode 100644 BKPS/14031218/Documents/Diagrams/Position Protection.drawio create mode 100644 BKPS/14031218/Documents/JsModules/x-color.tools.js create mode 100644 BKPS/14031218/Documents/JsModules/x-file.tools.js create mode 100644 BKPS/14031218/Documents/JsModules/x-shell.tools.js create mode 100644 BKPS/14031218/Documents/JsModules/x-type-detector.tools.js create mode 100644 BKPS/14031218/Documents/JsModules/x-value.tools.js create mode 100644 BKPS/14031218/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 create mode 100644 BKPS/14031218/Documents/Temlates/x-saherelm.x-panel.ea.mq5 create mode 100644 BKPS/14031218/Experts/Advisors/ExpertMACD.mq5 create mode 100644 BKPS/14031218/Experts/Advisors/ExpertMAMA.mq5 create mode 100644 BKPS/14031218/Experts/Advisors/ExpertMAPSAR.mq5 create mode 100644 BKPS/14031218/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 create mode 100644 BKPS/14031218/Experts/Examples/ChartInChart/ChartInChart.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Controls/Controls.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Controls/ControlsDialog.mqh create mode 100644 BKPS/14031218/Experts/Examples/Correlation Matrix 3D/Correlation Matrix 3D.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Correlation Matrix 3D/Correlation Matrix 3D.mqproj create mode 100644 BKPS/14031218/Experts/Examples/MACD/MACD Sample.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Math 3D Morpher/Functions.mqh create mode 100644 BKPS/14031218/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mqproj create mode 100644 BKPS/14031218/Experts/Examples/Math 3D Morpher/Textures/checker.bmp create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Functions.mqh create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Math 3D.ico create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Math 3D.mq5 create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Math 3D.mqproj create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Chomolungma.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/ClimberDream.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/DoubleScrew.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Granite.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Hedgehog.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Hill.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Josephine.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/MultyExtremalScrew.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Screw.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Sink.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Skin.set create mode 100644 BKPS/14031218/Experts/Examples/Math 3D/Sets/Trapfall.set create mode 100644 BKPS/14031218/Experts/Examples/Moving Average/Moving Average.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Harami CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Harami MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Harami RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish Harami Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/HangingMan Hammer CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/HangingMan Hammer MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/HangingMan Hammer RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/HangingMan Hammer Stoch.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji CCI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji MFI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji RSI.mq5 create mode 100644 BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji Stoch.mq5 create mode 100644 BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.ex5 create mode 100644 BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.x3ma.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xatr.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xcc.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xche.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xct.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xdon.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xhk.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xpv.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xstr.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xtrend.helper.mq5 create mode 100644 BKPS/14031218/Helpers/x-saherelm.x121.xvwap.helper.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.x3ma.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.x3ma.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xatr.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xatr.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xcc.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xcc.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xche.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xche.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xct.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xct.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xdon.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xdon.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xhk.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xhk.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xpv.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xpv.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xstr.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xstr.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xtrend.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xtrend.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xvwap.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xvwap.mq5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xwz.ex5 create mode 100644 BKPS/14031218/Indicators/x-saherelm.x121.xwz.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.common.lib.ex5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.common.lib.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.draw.lib.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.extensions.lib.ex5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.extensions.lib.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.lib.ex5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.lib.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.ex5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.mq5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-trade.lib.ex5 create mode 100644 BKPS/14031218/Libraries/x-saherelm.x-trade.lib.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Experts/x-121.smc.expert.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Libraries/x-121.smc.guard.lib.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Libraries/x-121.smc.guard.lib.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.class.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.class.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.mq5 create mode 100644 BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.ex5 create mode 100644 BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 diff --git a/BKPS/14031218/Classes/x-saherelm.base.class.mq5 b/BKPS/14031218/Classes/x-saherelm.base.class.mq5 new file mode 100644 index 0000000..0e7557f --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.base.class.mq5 @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XBaseClass +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// XBase Class ... +class XCBase +{ + // + // Public ... + public: + // + // Protected ... + + // + // Represent Basic Unique Tag ... + virtual string GetTag() { + return NULL; + } + + // + // Retrieve Class Token ... + virtual string GetToken() { + return NULL; + } + + // + // Protected + protected: + // + // Private ... + private: +}; + +// +template +string GenerateSpecifiedCommonSummary( + T &mItem, + string separator = "\n", + bool includeScores = true, + bool setLabel = false // +) +{ + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + mItem.GenerateScore( + bullishScore, + bearishScore // + ); + + // + result = + // + (!setLabel + ? "" + : "Commons:" + separator) + + "---------------" + separator + + "Symbol: " + mItem.symbol + separator + + "Period: " + ToString(mItem.period) + separator + + "Time: " + ToString(mItem.time) + separator + + (includeScores + ? "---------------" + separator + + "Scores:" + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "---------------" + separator + : "") + + "" + // + ; + + // + return result; +} + +// diff --git a/BKPS/14031218/Classes/x-saherelm.x-account.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-account.class.mq5 new file mode 100644 index 0000000..c451091 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-account.class.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAccount +// Description: provides all Account requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XCAccount : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCAccount() + { + // + mAccountInfo = new CAccountInfo(); + } + + // + // Deconstructor ... + void ~XCAccount() + { + } + + // + // START Provided Functions ... + // + + // + // User Account ... + long GetUserAccount() + { + return mAccountInfo.Login(); + } + + // + // Account Leverage ... + long GetLeverage() + { + return mAccountInfo.Leverage(); + } + + // + // Get Trade Expert State ... + bool CanExpertTrade() + { + return mAccountInfo.TradeExpert(); + } + + // + // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... + // -------------------------- + // ACCOUNT_TRADE_MODE_DEMO + // ACCOUNT_TRADE_MODE_CONTEST + // ACCOUNT_TRADE_MODE_REAL + ENUM_ACCOUNT_TRADE_MODE GetTradeMode() + { + return mAccountInfo.TradeMode(); + } + + // + // Get Account Balance ... + double GetBalance() + { + return mAccountInfo.Balance(); + } + + // + // Get the amount of give Credit ... + double GetCredit() + { + return mAccountInfo.Credit(); + } + + // + // Get the amount of current Profit on account ... + double GetProfit() + { + return mAccountInfo.Profit(); + } + + // + // Get the amount of current Equity on account ... + double GetEquity() + { + return mAccountInfo.Equity(); + } + + // + // Get the amount of reserved Margin ... + double GetMargin() + { + return mAccountInfo.Margin(); + } + + // + // Get the amount of free Margin ... + double GetFreeMargin() + { + return mAccountInfo.FreeMargin(); + } + + // + // Get the Level of Margin ... + double GetMarginLevel() + { + return mAccountInfo.MarginLevel(); + } + + // + // Get the Level Of Margin for a Deposit ... + double GetMarginCall() + { + return mAccountInfo.MarginCall(); + } + + // + // Get the Level of Margin for Stop out ... + double GetMarginStopOut() + { + return mAccountInfo.MarginStopOut(); + } + + // + // Get the Client Name ... + string GetName() + { + return mAccountInfo.Name(); + } + + // + // Get the Trade Server Name ... + string GetServerName() + { + return mAccountInfo.Server(); + } + + // + // Get deposit Currency Name ... + string GetCurrency() + { + return mAccountInfo.Currency(); + } + + // + // Get the Company Name that serves an Account ... + string GetCompany() + { + return mAccountInfo.Company(); + } + + // + // Calculate Profits for the current account based on passed parameters ... + double CalculateTradeProfit( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry, // open price + double exit // close price + ) + { + // + double result = mAccountInfo.OrderProfitCheck( + symbol, + type, + volume, + entry, + exit); + + // + return result; + } + + // + // Calculate amount of margin which required for trade operation ... + double CalculateMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.MarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate amount of free margin left after trade operation ... + double CalculateFreeMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.FreeMarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate the Maximum possible volume of trade operation ... + double CalculateMaxVolume( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double entry, // open price + double percent = 100 // percent of available margin + ) + { + // + double result = mAccountInfo.MaxLotCheck( + symbol, + type, + entry, + percent); + + // + return result; + } + + // + // Calculate Point Value for Given Symbol based on Account ... + double GetPointValue( + string symbol // trading symbol + ) + { + // + double result = 0; + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + double ticksPerPoint = tickSize / point; + + // + result = tickValue / ticksPerPoint; + + // + return result; + } + + // + // Calculate Risk Amount based on account Currency by Providing: + // Points and Volume ... + double CalculateRiskAmount( + string symbol, // trading symbol + double points, // amount of Risk Points + double volume // position Volume + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = pointValue * volume * points; + + // + return result; + } + + // + // Calculate Risk Points based on account Currency by Providing: + // Volume and Amount ... + double CalculateRiskPoints( + string symbol, // trading symbol + double volume, // position Volume + double amount // amount of Risk based on Account Currency + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * volume); + + // + return result; + } + + // + // Calculate Volume based on account Currency by Providing: + // Amount and Risk Points ... + double CalculateVolume( + string symbol, // trading symbol + double amount, // amount of Risk based on Account Currency + double points // amount of Risk Points + ) + { + // + double result = 0; + + // + points = + points <= 0 + ? 10 + : points; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * points); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Account Info ... + CAccountInfo mAccountInfo; +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/BKPS/14031218/Classes/x-saherelm.x-alert.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-alert.class.mq5 new file mode 100644 index 0000000..c92a6d5 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-alert.class.mq5 @@ -0,0 +1,1580 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAlert +// Description: provides all Alerts requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Class Definition ... + +class XCAlert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCAlert( + string prefix = "X-Alert", // Alerts Prefixe + bool enableAlerts = true, // Enable Alerts + bool logAlerts = true, // Log Alerts + bool terminalAlerts = false, // Terminal Alerts + bool mailAlerts = false, // Mail Alerts + bool pushAlerts = false // Push Alerts + ) + { + // + mPrefix = prefix; + mLogAlerts = logAlerts; + mMailAlerts = mailAlerts; + mPushAlerts = pushAlerts; + mEnableAlerts = enableAlerts; + mTerminalAlerts = terminalAlerts; + + // + // Normalize Prefix if Not Provided ... + if (!IsValid(mPrefix)) + { + mPrefix = GetTag(); + } + } + + // + // Deconstructor ... + ~XCAlert() + { + } + + // + // Override ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // + // Properties Getter(s) / Setter(s) ... + + // + string GetPrefix() + { + return mPrefix; + } + + // + void SetPrefix(string value) + { + mPrefix = value; + } + + // + bool GetLogAlerts() + { + return mLogAlerts; + } + + // + void SetLogAlerts(bool value) + { + mLogAlerts = value; + } + + // + bool GetEnableAlerts() + { + return mEnableAlerts; + } + + // + void SetEnableAlerts(bool value) + { + mEnableAlerts = value; + } + + // + bool GetPushAlerts() + { + return mPushAlerts; + } + + // + void SetPushAlerts(bool value) + { + mPushAlerts = value; + } + + // + bool GetMailAlerts() + { + return mMailAlerts; + } + + // + void SetMailAlerts(bool value) + { + mMailAlerts = value; + } + + // + bool GetTerminalAlerts() + { + return mTerminalAlerts; + } + + // + void SetTerminalAlerts(bool value) + { + mTerminalAlerts = value; + } + + // + // Tools Funtions ... + + // + // Alerts ... + + // + // Logging an Alert ... + void LogAlert(string message) + { + // + // Validate Args ... + if (!CanLogAlert()) + { + return; + } + + // + Log(message); + } + + // + // Terminal Alert ... + void TerminalAlert(string message) + { + // + // Validate Args ... + if (!CanTerminalAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // Send Terminal Alert ... + Alert(message); + } + + // + // Mail Alert ... + void MailAlert(string message) + { + // + // Validate Args ... + if (!CanMailAlert()) + { + return; + } + + // + // Send Mail Alert ... + SendMail(GetPrefix(), message); + } + + // + // Send Push Notification ... + void PushAlert(string message) + { + // + // Validate Args ... + if (!CanPushAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // + // Send Push Notification Alert ... + SendNotification(message); + } + + // + // Send an Alert by Handling all Different Specified + // type's of Alert's if they are Enabled ... + void Alert(string message) + { + // + // Handle Log, if Enabled ... + LogAlert(message); + + // + // Handle Mail if Enabled ... + MailAlert(message); + + // + // Handle Push if Enabled ... + PushAlert(message); + + // + // Handle Terminal if Enabled ... + TerminalAlert(message); + } + + // + // Logs ... + + // + // Log a Message ... + void Log(string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), " > ", message); + } + void Log(string tag, string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), "_", tag, " > ", message); + } + void LogEmpty() + { + // + if (!CanLog()) + { + return; + } + + // + Print(" "); + } + + // + // Log Specific Array ... + template + void LogArray( + T &array[], // Array to Log + string label = NULL // Array Label + ) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), ">", (IsValid(label) ? label : "")); + ArrayPrint(array); + } + + // + // Error ... + + // + // Log an Error ... + void LogError( + int error = -1 // Specific Error, if it's equal to -1, use Last Error ... + ) + { + // + if (!CanLog()) + { + return; + } + + // + if (error <= -1) + { + error = GetLastError(); + } + + // + string errorMsg = GetErrorDescription(error); + + // + Log("Error: " + errorMsg); + } + + // + // Retrieve Specified Error Code Description ... + string GetErrorDescription(int err_code) + { + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; + } + + // + // Retrieve Specified Error Code Description ... + string GetTradeServerReturnCodeDescription(int return_code) + { + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + + // + bool CanLog() + { + return mLogAlerts; + } + + // + bool CanLogAlert() + { + // + bool result = GetEnableAlerts() && GetLogAlerts(); + + // + return result; + } + + // + bool CanTerminalAlert() + { + // + bool result = GetEnableAlerts() && GetTerminalAlerts(); + + // + return result; + } + + // + bool CanMailAlert() + { + // + bool result = GetEnableAlerts() && GetMailAlerts(); + + // + return result; + } + + // + bool CanPushAlert() + { + // + bool result = GetEnableAlerts() && GetPushAlerts(); + + // + return result; + } + + private: + // + // Props ... + string mPrefix; // Alerts Prefixe + bool mEnableAlerts; // Enable Alerts + bool mLogAlerts; // Log Alerts + bool mTerminalAlerts; // Terminal Alerts + bool mMailAlerts; // Mail Alerts + bool mPushAlerts; // Push Alerts + + // + // Tools ... + + // + // Clear Escape String and + // Attach Alert Prefix to Message ... + string PrepareMessage(string message) + { + // + StringReplace(message, "\n", " | "); + + // + StringConcatenate(message, GetPrefix(), " > ", message); + + // + return message; + } +}; + +// +// a Base Class by Support Alert ... +class XCBaseAlert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor(s) ... + void XCBaseAlert() + { + // + // Instance Alert ... + mAlert = new XCAlert(); + } + + // + // Deconstructors ... + void ~XCBaseAlert() + { + // + delete mAlert; + + // + ZeroMemory(mAlert); + } + + // + // Alert Handler Functions ... + + // + // Alert Functions Getter(s) / Setters(s) ... + + // + string GetAlertPrefix() + { + return mAlert.GetPrefix(); + } + + // + void SetAlertPrefix(string value) + { + mAlert.SetPrefix(value); + } + + // + bool GetAlertLogAlerts() + { + return mAlert.GetLogAlerts(); + } + + // + void SetAlertLogAlerts(bool value) + { + mAlert.SetLogAlerts(value); + } + + // + bool GetAlertEnableAlerts() + { + return mAlert.GetEnableAlerts(); + } + + // + void SetAlertEnableAlerts(bool value) + { + mAlert.SetEnableAlerts(value); + } + + // + bool GetAlertPushAlerts() + { + return mAlert.GetPushAlerts(); + } + + // + void SetAlertPushAlerts(bool value) + { + mAlert.SetPushAlerts(value); + } + + // + bool GetAlertMailAlerts() + { + return mAlert.GetMailAlerts(); + } + + // + void SetAlertMailAlerts(bool value) + { + mAlert.SetMailAlerts(value); + } + + // + bool GetAlertTerminalAlerts() + { + return mAlert.GetTerminalAlerts(); + } + + // + void SetAlertTerminalAlerts(bool value) + { + mAlert.SetTerminalAlerts(value); + } + + // + // Alert Actions ... + + // + // Logging an Alert ... + void LogAlert(string message) + { + mAlert.LogAlert(message); + } + + // + // Terminal Alert ... + void TerminalAlert(string message) + { + mAlert.TerminalAlert(message); + } + + // + // Mail Alert ... + void MailAlert(string message) + { + mAlert.MailAlert(message); + } + + // + // Send Push Notification ... + void PushAlert(string message) + { + mAlert.PushAlert(message); + } + + // + // Send an Alert by Handling all Different Specified + // type's of Alert's if they are Enabled ... + void Alert(string message) + { + mAlert.Alert(message); + } + + // + // Logs ... + + // + // Log a Message ... + void Log(string message) + { + mAlert.Log(message); + } + void Log(string tag, string message) + { + mAlert.Log(tag, message); + } + void LogEmpty() + { + mAlert.LogEmpty(); + } + + // + // Log Specific Array ... + template + void LogArray( + T &array[], // Array to Log + string label = NULL // Array Label + ) + { + mAlert.LogArray(array, label); + } + + // + // Error ... + + // + // Log an Error ... + void LogError( + int error = -1 // Specific Error, if it's equal to -1, use Last Error ... + ) + { + mAlert.LogError(error); + } + + // + // Retrieve Specified Error Code Description ... + string GetErrorDescription(int err_code) + { + return mAlert.GetErrorDescription(err_code); + } + + // + // Retrieve Specified Error Code Description ... + string GetTradeServerReturnCodeDescription(int return_code) + { + return mAlert.GetTradeServerReturnCodeDescription(return_code); + } + + // + // Protected ... + protected: + // + // Alert ... + XCAlert *mAlert; + + // + // Private ... + private: +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-app-dialog.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-app-dialog.class.mq5 new file mode 100644 index 0000000..6bfa4d9 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-app-dialog.class.mq5 @@ -0,0 +1,275 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCPanel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include + +// +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Extentions ... + +/** + * Check a Qery Contains in a Content or not ... + * + * @param mQuery: String ... + * @param mContent: String ... + * @param ignoreCase: Boolean ... + * + * @return ( bool ) + */ +bool XContains( + string mQuery, // Search String + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + return Contains( + mQuery, + mContent, + ignoreCase // + ); +} + +// +// Implementation ... + +// +// a Base App Dialog Class ... +class XCAppDialog : public CAppDialog +{ + public: + // + // Action ... + + // + // Virual ... + + /** + * Override Close Button Click Action ... + */ + void OnClickButtonClose() + { + // + bool isClosed = ConfirmDialog("Close EA ?"); + + // + if (isClosed) + { + Destroy(); + } + } + + // + // Configuration Actions ... + + /** + * Show or Hide Minimize Button ... + * + * @param show: boolean + */ + void MinimizeButton(bool show) + { + // + int controlIDX = ControlFind("MinMax"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Show or Hide Close Button ... + * + * @param show: boolean + */ + void CloseButton(bool show) + { + // + int controlIDX = ControlFind("Close"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Minimize Functionality Implementation ... + */ + void Minimize() + { + // + m_minimized = true; + Rebound(m_min_rect); + ClientAreaVisible(false); + } + + /** + * Set Background Color ... + * + * @param clr: Color ... + */ + void BackgroundColor(color clr) + { + // + int controlIDX = ControlFind("Client"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + CWnd *obj = Control(controlIDX); + CWndClient *wndclient = (CWndClient *)obj; + + // + wndclient.ColorBackground(clr); + } + + // + protected: + // + + /** + * Find Specific Control in Dialog ... + * + * @param name: String to Search + * + * @return ( int ) + */ + int ControlFind(string name) + { + // + int result = -1; + + // + if (!IsValid(name)) + { + return result; + } + + // + int count = ControlsTotal(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + string iName = Control(i).Name(); + + // + bool isContains = XContains( + name, + iName, + true // Ignore Case ... + ); + if (isContains) + { + // + result = i; + break; + } + } + + // + return result; + } + + /** + * Create and Run Confirm Dialog ... + * + * @param message: message for Message Box ... + * + * @return ( bool ) + */ + bool ConfirmDialog(string message = NULL) + { + // + bool result = false; + + // + if (!IsValid(message)) + { + message = "Confirm ?"; + } + + // + int dialogResult = MessageBox(message, NULL, MB_YESNO); + + // + // use 'switch' or 'if' as needed + switch (dialogResult) + { + // + // Yes ... + case IDYES: + result = true; + break; + // + // No ... + case IDNO: + result = false; + break; + // + // Cancel ... + case IDCANCEL: + result = false; + break; + } + + // + return result; + } + + // + private: + // + + // +}; \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-bar.analyser.class.ex5 b/BKPS/14031218/Classes/x-saherelm.x-bar.analyser.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..455bf0c2ac27c93057da20ca7a93f6816234c5bb GIT binary patch literal 8044 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 1; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Retrieve Loopback HH & LL Data ... + * + * @param hhIDX: Integer, HH Index ... + * @param hh: Double, HH Value ... + * @param llIDX: Integer, LL Index ... + * @param ll: Double, LL Value ... + * @param bar: XOHCL instance ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool CalculateLoopbackHLData( + int &hhIDX, + double &hh, + int &llIDX, + double &ll, + XOHCL &bar, + int loopback // + ) + { + // + bool result = false; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + int index = -1; + int start = -1; + int end = -1; + int count = -1; + result = CalculateLoopBackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + hhIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + count, + start // + ); + result = IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + llIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + count, + start // + ); + result = IsValidIndex(llIDX); + if (!result) + { + return result; + } + + // + hh = iHigh( + bar.symbol, + bar.period, + hhIDX // + ); + ll = iLow( + bar.symbol, + bar.period, + llIDX // + ); + + // + return result; + } + + /** + * Calculate Bar Range ... + * + * @param bar: XOHCL instance ... + * + * @return ( double ) + */ + double GetBarRangePercent(XOHCL &bar) + { + // + double result = 0; + + // + result = bar.GetRange() / 100; + + // + return result; + } + + /** + * Detect Same Bars ... + * + * @param bar: XOHCL instance, Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Holds Result Direction ... + * @param index: Integer, Holds Result Index ... + * @param sameBars: Iteger, Required Same Bar ... + * + * @return ( bool ) + */ + bool HasSameBars( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int &index, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + index = bar.Index() + 1; + bool canContinue = true; + int sameBullishBarsFounded = 0; + int sameBearishBarsFounded = 0; + bool canContinueForBullish = true; + bool canContinueForBearish = true; + while (canContinue) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + index // + ); + if (!result) + { + break; + } + + // + bool isBullish = iBar.IsBullish(); + bool isBearish = iBar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + break; + } + + // + if (isBullish) + { + // + sameBullishBarsFounded++; + canContinueForBearish = false; + } + else if (isBearish) + { + // + sameBearishBarsFounded++; + canContinueForBullish = false; + } + else + { + // + sameBullishBarsFounded = 0; + sameBearishBarsFounded = 0; + canContinueForBullish = false; + canContinueForBearish = false; + } + + // + result = canContinueForBullish || + canContinueForBearish; + if (!result) + { + break; + } + + // + canContinueForBullish = + canContinueForBullish && + sameBullishBarsFounded > 0; + + // + canContinueForBearish = + canContinueForBearish && + sameBearishBarsFounded > 0; + + // + canContinue = + canContinueForBullish || + canContinueForBearish; + if (canContinue) + { + index++; + } + } + + // + bool hasBullishSameBars = + sameBullishBarsFounded >= sameBars; + + // + bool hasBearishSameBars = + sameBearishBarsFounded >= sameBars; + + // + result = hasBullishSameBars || + hasBearishSameBars; + if (!result) + { + return result; + } + + // + index--; + + // + dir = + hasBullishSameBars + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Detect Price Consolidation ... + * + * @param bar: XOHCL instance Reference, Start Bar ... + * @param loopback: Integer, Consolidation Length Finder ... + * @param consolidationRange: Integer, Consolidation Range Finder ... + * @param upper: Double Reference ... + * @param lower: Double Reference ... + * @param upperAppliedTo: ENUM_APPLIED_PRICE member, Upper Price ... + * @param lowerAppliedTo: ENUM_APPLIED_PRICE member, Lower Price ... + * + * @return ( bool ) + */ + bool IsConsolidate( + XOHCL &bar, + double &upper, + double &lower, + int loopback = 30, + int consolidationRange = 50, + ENUM_APPLIED_PRICE upperAppliedTo = PRICE_HIGH, + ENUM_APPLIED_PRICE lowerAppliedTo = PRICE_LOW // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + if (loopback < 7) + { + loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double points = GetPoints(bar.symbol); + int index = bar.Index(); + + // + double upperPrice[]; + int upperPriceCount = FillPrice( + upperPrice, + upperAppliedTo, + bar.symbol, + bar.period, + index, + loopback // + ); + + // + double lowerPrice[]; + int lowerPriceCount = FillPrice( + lowerPrice, + lowerAppliedTo, + bar.symbol, + bar.period, + index, + loopback // + ); + + // + result = upperPriceCount == lowerPriceCount && + lowerPriceCount == loopback; + if (!result) + { + return result; + } + + // + upper = upperPrice[ArrayMaximum(upperPrice)]; + lower = lowerPrice[ArrayMinimum(lowerPrice)]; + + // + double range = upper - lower; + result = range <= consolidationRange * points; + + // + return result; + } + + bool HasConsolidationZone( + XOHCL &bar, + XConsolidationZone &zone, + int minLoopback = 3, + double range = 50, + ENUM_APPLIED_PRICE upperAppliedTo = PRICE_HIGH, + ENUM_APPLIED_PRICE lowerAppliedTo = PRICE_LOW // + ) + { + // + bool result = false; + + // + zone.Clean(); + + // + result = bar.IsValid() && + minLoopback > 0 && + range > 0; + if (!result) + { + return result; + } + + // + double points = GetPoints(bar.symbol); + int index = bar.Index() + 1; + int length = minLoopback; + + // + double upperPrice[]; + int upperPriceCount = FillPrice( + upperPrice, + upperAppliedTo, + bar.symbol, + bar.period, + index, + length // + ); + + // + double lowerPrice[]; + int lowerPriceCount = FillPrice( + lowerPrice, + lowerAppliedTo, + bar.symbol, + bar.period, + index, + length // + ); + + // + result = upperPriceCount == lowerPriceCount && + lowerPriceCount == length; + if (!result) + { + // + Clean(upperPrice); + Clean(lowerPrice); + + // + return result; + } + + // + double upper = upperPrice[ArrayMaximum(upperPrice)]; + double lower = lowerPrice[ArrayMinimum(lowerPrice)]; + + // + bool isBullishBreake = + bar.low > lower && + bar.high > upper && + bar.GetUp() > upper; + bool isBearishBreake = + bar.high < upper && + bar.low < lower && + bar.GetDown() < lower; + result = isBullishBreake || + isBearishBreake; + if (!result) + { + // + Clean(upperPrice); + Clean(lowerPrice); + + // + return result; + } + + // + double delta = upper - lower; + result = delta <= range * points; + if (!result) + { + // + Clean(upperPrice); + Clean(lowerPrice); + + // + return result; + } + + // + while (delta <= range * points) + { + // + length++; + + // + upperPriceCount = FillPrice( + upperPrice, + upperAppliedTo, + bar.symbol, + bar.period, + index, + length // + ); + + // + lowerPriceCount = FillPrice( + lowerPrice, + lowerAppliedTo, + bar.symbol, + bar.period, + index, + length // + ); + + // + bool isValid = upperPriceCount == lowerPriceCount && + lowerPriceCount == length; + if (!isValid) + { + break; + } + + // + double iUpper = upperPrice[ArrayMaximum(upperPrice)]; + double iLower = lowerPrice[ArrayMinimum(lowerPrice)]; + + // + delta = iUpper - iLower; + if (delta <= range * points) + { + // + upper = iUpper; + lower = iLower; + } + } + + // + Clean(upperPrice); + Clean(lowerPrice); + + // + // Filling Zone ... + zone.upper = upper; + zone.lower = lower; + zone.symbol = bar.symbol; + zone.period = bar.period; + zone.to = iTime( + bar.symbol, + bar.period, + bar.Index() + 1 // + ); + zone.from = iTime( + bar.symbol, + bar.period, + bar.Index() + length // + ); + zone.dir = isBullishBreake + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = zone.IsValid(); + if (!result) + { + zone.Clean(); + } + + // + return result; + } + + /** + * Check Bar Has Bullish Trend or not ... + * + * @param bar: XOHCL instance ... + * @param forceAll: Boolean ... + * + * @return ( bool ) + */ + bool HasBullishTrend( + XOHCL &bar, + bool forceAll = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + bool trend1 = HasBullishTrend( + bar, + tmpHSW, + tmpLSW, + true // + ); + + // + bool trend2 = HasBullishTrend( + bar, + tmpHSW, + tmpLSW, + false // + ); + + // + if (!forceAll) + { + // + result = trend1; + if (!result) + { + return result; + } + } + + // + result = + trend1 || + trend2; + + // + return result; + } + + /** + * Check Bar Has Bearish Trend or not ... + * + * @param bar: XOHCL instance ... + * @param forceAll: Boolean ... + * + * @return ( bool ) + */ + bool HasBearishTrend( + XOHCL &bar, + bool forceAll = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + bool trend1 = HasBearishTrend( + bar, + tmpHSW, + tmpLSW, + true // + ); + + // + bool trend2 = HasBearishTrend( + bar, + tmpHSW, + tmpLSW, + false // + ); + + // + if (!forceAll) + { + // + result = trend1; + if (!result) + { + return result; + } + } + + // + result = + trend1 || + trend2; + + // + return result; + } + + /** + * Check Specified Bar Has Bullish Pattern or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length for Patterns ... + * @param verifications: Integer, Number of Given Verifications ... + * @param checkHammer: Boolean, Specified Check Hammer Pattern ... + * @param checkMorningStar: Boolean, Specified Check Morning Star Pattern ... + * @param checkBullishMarubozu: Boolean, Specified Check Marubozu Pattern ... + * @param checkBullishEngulfing: Boolean, Specified Check Engulfing Pattern ... + * + * @return ( bool ) + */ + bool HasBullishPattern( + XOHCL &bar, + int loopback = 0, + int verifications = 1, + bool checkHammer = true, + bool checkMorningStar = true, + bool checkBullishMarubozu = true, + bool checkBullishEngulfing = true // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (verifications <= 0) + { + verifications = 1; + } + + // + int founded = 0; + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + loopback; i++) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + bool isHammer = + !checkHammer + ? false + : IsHammer(iBar); + if (isHammer) + { + founded++; + } + + // + bool isMorningStar = + !checkMorningStar + ? false + : IsMorningStar(iBar); + if (isMorningStar) + { + founded++; + } + + // + bool isBullishMarubozu = + !checkBullishMarubozu + ? false + : IsBullishMarubozu(iBar); + if (isBullishMarubozu) + { + founded++; + } + + // + bool isBullishEngulfing = + !checkBullishEngulfing + ? false + : IsBullishEngulfing(iBar); + if (isBullishEngulfing) + { + founded++; + } + + // + } + + // + result = + result && + founded >= verifications; + + // + return result; + } + + /** + * Check Specified Bar Has Bearish Pattern or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length for Patterns ... + * @param verifications: Integer, Number of Given Verifications ... + * @param checkShootingStar: Boolean, Specified Check Shooting Star Pattern ... + * @param checkEveningStar: Boolean, Specified Check Evening Star Pattern ... + * @param checkBearishMarubozu: Boolean, Specified Check Marubozu Pattern ... + * @param checkBearishEngulfing: Boolean, Specified Check Engulfing Pattern ... + * + * @return ( bool ) + */ + bool HasBearishPattern( + XOHCL &bar, + int loopback = 0, + int verifications = 1, + bool checkShootingStar = true, + bool checkEveningStar = true, + bool checkBearishMarubozu = true, + bool checkBearishEngulfing = true // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (verifications <= 0) + { + verifications = 1; + } + + // + int founded = 0; + + // + int idx = bar.Index(); + for (int i = idx - 1; i <= idx + loopback; i++) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + bool isShootingStar = + !checkShootingStar + ? false + : IsShootingStar(iBar); + if (isShootingStar) + { + founded++; + } + + // + bool isEveningStar = + !checkEveningStar + ? false + : IsEveningStar(iBar); + if (isEveningStar) + { + founded++; + } + + // + bool isBearishMarubozu = + !checkBearishMarubozu + ? false + : IsBearishMarubozu(iBar); + if (isBearishMarubozu) + { + founded++; + } + + // + bool isBearishEngulfing = + !checkBearishEngulfing + ? false + : IsBearishEngulfing(iBar); + if (isBearishEngulfing) + { + founded++; + } + + // + } + + // + result = + result && + founded >= verifications; + + // + return result; + } + + // + // Commons ... + + /** + * Check Specified Bar's Range is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool HasExtendedRange( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + if (loopback < 3) + { + loopback = 3; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + int start = index + 1; + int end = start + loopback; + int count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + double sum = 0; + XOHCL iBar = bar; + for (int i = start; i < end; i++) + { + // + bool isRetrieved = iBar.GetPreviousBar(iBar); + if (!isRetrieved) + { + continue; + } + + // + sum += iBar.GetRange(); + } + + // + result = sum > 0; + if (!result) + { + return result; + } + + // + double avg = sum / count; + + // + result = bar.GetRange() >= avg; + + // + return result; + } + + /** + * Check Specified Bar's Body is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool HasExtendedBody( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + if (loopback < 3) + { + loopback = 3; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + int start = index + 1; + int end = start + loopback; + int count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + double sum = 0; + XOHCL iBar = bar; + for (int i = start; i < end; i++) + { + // + bool isRetrieved = iBar.GetPreviousBar(iBar); + if (!isRetrieved) + { + continue; + } + + // + sum += iBar.GetBody(); + } + + // + result = sum > 0; + if (!result) + { + return result; + } + + // + double avg = sum / count; + + // + result = bar.GetBody() >= avg; + + // + return result; + } + + /** + * Check Specified Bar's Body and Range is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool IsExtended( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + bool hasExtendedBody = HasExtendedBody(bar, loopback); + bool hasExtendedRange = HasExtendedRange(bar, loopback); + result = hasExtendedBody && + hasExtendedRange; + + // + return result; + } + + /** + * Check Specified Bar is Swing High or not ... + * + * @param bar: XOHCL instnce ... + * @param range: Integer, Specified Range ... + * + * @return ( bool ) + */ + bool IsSwingHigh( + XOHCL &bar, + int range = 2 // + ) + { + // + bool result = false; + + // + if (range < 1) + { + range = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + index + i // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + index - i // + ); + if (!result) + { + break; + } + + // + result = bar.high >= iPrevBar.high && + bar.high >= iNextBar.high; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check Specified Bar is Swing Low or not ... + * + * @param bar: XOHCL instnce ... + * @param range: Integer, Specified Range ... + * + * @return ( bool ) + */ + bool IsSwingLow( + XOHCL &bar, + int range = 2 // + ) + { + // + bool result = false; + + // + if (range < 1) + { + range = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + index + i // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + index - i // + ); + if (!result) + { + break; + } + + // + result = bar.low <= iPrevBar.low && + bar.low <= iNextBar.low; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check Specified Bar is Swing or not ... + * + * @param bar: XOHCL instnce ... + * @param dir: ENUM_X_DIRECTION member ... + * @param range: Integer, Specified Range ... + * + * @return ( bool ) + */ + bool IsSwing( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int range = 2 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + bool isSwingLow = IsSwingLow(bar, range); + bool isSwingHigh = IsSwingHigh(bar, range); + + // + result = isSwingLow || + isSwingHigh; + if (result) + { + // + if (isSwingLow) + { + dir = X_DIRECTION_BULLISH; + } + else + { + dir = X_DIRECTION_BEARISH; + } + } + + // + return result; + } + + /** + * Check a Bar is Momentum Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsMomentumBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double bodyPercent = 70 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (bodyPercent < 50) + { + bodyPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + bar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + double body = bar.GetBody(); + double rp = GetBarRangePercent(bar); + + // + result = body >= rp * bodyPercent; + + // + if (result) + { + // + dir = + bar.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + /** + * Check a Bar is Rejection Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowPercent: Double ... + * + * @return ( bool ) + */ + bool IsRejectionBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowPercent = 60 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (shadowPercent < 50) + { + shadowPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + bar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + double body = bar.GetBody(); + double range = bar.GetRange(); + double shadows = bar.GetShadows(); + double lowShadow = bar.GetLowShadow(); + double highShadow = bar.GetHighShadow(); + double rp = GetBarRangePercent(bar); + + // + result = shadows >= rp * shadowPercent; + + // + if (result) + { + // + dir = + lowShadow > highShadow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + /** + * Check Specified Bar is Engulfing Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsEngulfBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double bodyPercent = 60 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (bodyPercent < 50) + { + bodyPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + pBar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + // Check Engulfig ... + result = + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown(); + if (!result) + { + return result; + } + + // + // Check Engulfing Direction ... + bool isBullishEngulfed = + pBar.IsBearish() && + bar.IsBullish(); + bool isBearishEngulfed = + pBar.IsBullish() && + bar.IsBearish(); + + // + result = isBullishEngulfed || + isBearishEngulfed; + if (!result) + { + return result; + } + + // + dir = isBullishEngulfed + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Check Specified Bar is Pin Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowPercent: Double ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsPinBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowPercent = 65, + double bodyPercent = 25 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0 && + bodyPercent > 0 && + shadowPercent > 0 && + bodyPercent < shadowPercent; + if (!result) + { + return result; + } + + // + // Chack Range Extends ... + if (extend > 0) + { + // + result = HasExtendedRange( + bar, + extend // + ); + if (!result) + { + return result; + } + } + + // + // Check Body ... + double rangePercent = GetBarRangePercent(bar); + result = rangePercent > 0; + if (!result) + { + return result; + } + + // + double body = bar.GetBody(); + double highShadow = bar.GetHighShadow(); + double lowShadow = bar.GetLowShadow(); + + // + // Check Body ... + result = body / rangePercent >= bodyPercent; + if (!result) + { + return result; + } + + // + bool isPassedHighShadow = + highShadow / rangePercent >= shadowPercent; + bool isPassedLowShadow = + lowShadow / rangePercent >= shadowPercent; + result = + isPassedLowShadow || + isPassedHighShadow; + if (!result) + { + return result; + } + + // + dir = isPassedLowShadow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Decision Bar (Pin, Momentum or Rejection) ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowForPinAndRejectionBarPercent: Double ... + * @param bodyForPinBarPercent: Double ... + * @param bodyForEngulfBarPercent: Double ... + * @param bodyForMomentumBarPercent: Double ... + * + * @return ( bool ) + */ + bool IsDecisionBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowForPinAndRejectionBarPercent = 65, + double bodyForPinBarPercent = 25, + double bodyForEngulfBarPercent = 65, + double bodyForMomentumBarPercent = 70 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Pin Bar ... + ENUM_X_DIRECTION pinDir; + bool isPiBar = IsPinBar( + bar, + pinDir, + extend, + shadowForPinAndRejectionBarPercent, + bodyForPinBarPercent // + ); + + // + // Engulfing Bar ... + ENUM_X_DIRECTION engulfDir; + bool isEngulfBar = IsEngulfBar( + bar, + engulfDir, + extend, + bodyForEngulfBarPercent // + ); + + // + // Momentum Bar ... + ENUM_X_DIRECTION momentumDir; + bool isMomentumBar = IsMomentumBar( + bar, + momentumDir, + extend, + bodyForMomentumBarPercent // + ); + + // + // Rejection Bar ... + ENUM_X_DIRECTION rejectionDir; + bool isRejectionBar = IsRejectionBar( + bar, + rejectionDir, + extend, + shadowForPinAndRejectionBarPercent // + ); + + // + result = isPiBar || + isEngulfBar || + isMomentumBar || + isRejectionBar; + if (result) + { + // + if (isPiBar) + { + dir = pinDir; + } + else if (isEngulfBar) + { + dir = engulfDir; + } + else if (isMomentumBar) + { + dir = momentumDir; + } + else + { + dir = rejectionDir; + } + } + + // + result = IsBullish(dir) || + IsBearish(dir); + + // + return result; + } + + /** + * Check Fibonacci Level 382 Pressure ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool HasFiboPressure( + XOHCL &bar, + ENUM_X_DIRECTION forDir, + ENUM_X_FIBO_LEVELS level // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + bool isBearish = IsBearish(forDir); + + // + double fiboLevelValue = GetFibonacciLevel( + bar.high, + bar.low, + level, + forDir // + ); + + // + bool isBullishPressured = + isBullish && + bar.GetDown() > fiboLevelValue; + bool isBearishPressured = + isBearish && + bar.GetUp() < fiboLevelValue; + + // + result = isBullishPressured || + isBearishPressured; + + // + return result; + } + + // + // Support and Resistance Zones ... + + /** + * Check a Bar is Support Bar or not ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Specified Verifiation Range ... + * + * @return ( bool ) + */ + bool IsSupport( + XOHCL &bar, + int range = 21 // + ) + { + // + bool result = false; + + // + if (range < 2) + { + range = 2; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + int prevIDX = index + i; + int nextIDX = index - 1; + + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + prevIDX // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + nextIDX // + ); + if (!result) + { + break; + } + + // + result = bar.low <= iPrevBar.low && + bar.low <= iNextBar.low; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check a Bar Has Support or not ... + * + * @param bar: XOHCL instance ... + * @param supportBar: XOHCL instance Specified Support Bar ... + * @param rage: int, + * @return ( bool ) + */ + bool HasSupport( + XOHCL &bar, + XOHCL &supportBar, + int range = 21 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + range; + result = IsValidIndex(barIndex); + if (!result) + { + // + supportBar.Clean(); + return result; + } + result = supportBar.Init( + bar.symbol, + bar.period, + barIndex // + ); + + // + result = supportBar.low < supportBar.GetDown(); + if (!result) + { + // + supportBar.Clean(); + return result; + } + + // + double selectedValue = supportBar.GetDown(); + + // + int llIDX = bar.FindLowestIndex(range - 1, MODE_LOW); + result = IsValidIndex(llIDX); + if (!result) + { + // + supportBar.Clean(); + return result; + } + + // + double llValue = iLow( + bar.symbol, + bar.period, + llIDX // + ); + + // + result = llValue >= selectedValue; + if (!result) + { + // + supportBar.Clean(); + return result; + } + + // + result = supportBar.IsValid(); + + // + return result; + } + + /** + * Check a Bar is Resistance Bar or not ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Specified Verifiation Range ... + * + * @return ( bool ) + */ + bool IsResistance( + XOHCL &bar, + int range = 21 // + ) + { + // + bool result = false; + + // + if (range < 2) + { + range = 2; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + int prevIDX = index + i; + int nextIDX = index - 1; + + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + prevIDX // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + nextIDX // + ); + if (!result) + { + break; + } + + // + result = bar.high >= iPrevBar.high && + bar.high >= iNextBar.high; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check a Bar Has Resistance or not ... + * + * @param bar: XOHCL instance ... + * @param resistanceBar: XOHCL instance Specified Resistance Bar ... + * @param rage: int, + * @return ( bool ) + */ + bool HasResistance( + XOHCL &bar, + XOHCL &resistanceBar, + int range = 21 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + range; + result = IsValidIndex(barIndex); + if (!result) + { + // + resistanceBar.Clean(); + return result; + } + result = resistanceBar.Init( + bar.symbol, + bar.period, + barIndex // + ); + + // + result = resistanceBar.low < resistanceBar.GetDown(); + if (!result) + { + // + resistanceBar.Clean(); + return result; + } + + // + double selectedValue = resistanceBar.GetUp(); + + // + int hhIDX = bar.FindHighestIndex(range - 1, MODE_HIGH); + result = IsValidIndex(hhIDX); + if (!result) + { + // + resistanceBar.Clean(); + return result; + } + + // + double hhValue = iHigh( + bar.symbol, + bar.period, + hhIDX // + ); + + // + result = hhValue >= selectedValue; + if (!result) + { + // + resistanceBar.Clean(); + return result; + } + + // + result = resistanceBar.IsValid(); + + // + return result; + } + + // + // Order Blocks ... + + /** + * Detect an Order Block Based on Given Bar ... + * + * @param bar: XOHCL instance, Specified Start Bar ... + * @param ob: XOHCL instance, Fill it if Order Block Found ... + * @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ... + * @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ... + * + * @return ( bool ) + */ + bool HasOrderBlock( + XOHCL &bar, + XOHCL &ob, + ENUM_X_DIRECTION &dir, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + ob.Clean(); + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = 0; + result = HasSameBars( + bar, + dir, + index, + sameBars // + ); + if (!result) + { + return result; + } + + // + int obIndex = index + 1; + result = ob.Init( + bar.symbol, + bar.period, + obIndex // + ); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Fair Value Gaps ... + + /** + * Detect a Fair Value Gap Based on Given Bar ... + * + * @param bar: XOHCL instance, Specified Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ... + * @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ... + * + * @return ( bool ) + */ + bool HasFairValueGap( + XOHCL &bar, + XOHCL &prevBar, + XOHCL &nextBar, + ENUM_X_DIRECTION &dir, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + prevBar.Clean(); + nextBar.Clean(); + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = 0; + result = HasSameBars( + bar, + dir, + index, + sameBars // + ); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(dir); + + // + int to = bar.Index(); + int from = + index > (to + sameBars) + ? to + sameBars + : index; + for (int i = from; i > to; i--) + { + // + result = prevBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + result = nextBar.Init( + bar.symbol, + bar.period, + i - 2 // + ); + if (!result) + { + break; + } + + // + result = isBullish + ? prevBar.high < nextBar.low + : prevBar.low > nextBar.high; + if (result) + { + break; + } + } + + // + if (!result) + { + // + prevBar.Clean(); + nextBar.Clean(); + dir = X_DIRECTION_NONE; + } + + // + return result; + } + + // + // Bar CHOCH ... + + /** + * Check Specified Bar Has PullBack or not ... + * + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param bar: XOHCL instance, Speciied Bar ... + * @param loopback: Integer, loopback Length ... + * @param forceBody: Boolean, Specified Choch Happens only by Bar's Body ... + * + * @return ( bool ) + */ + bool HasPullBack( + ENUM_X_DIRECTION &dir, + XOHCL &bar, + int loopback = 3, + bool forceBody = false // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + // Calculate Loopback Data ... + int index = -1; + int start = -1; + int end = -1; + int count = -1; + result = CalculateLoopBackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + // Calculate Loopback HH and LL Data ... + int hhIDX = -1; + double hh = -1; + int llIDX = -1; + double ll = -1; + result = CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + bool isBullishDirection = + bar.high > hh && + bar.low > ll; + bool isBearishDirection = + bar.high < hh && + bar.low < ll; + result = isBullishDirection || + isBearishDirection; + if (!result) + { + return result; + } + + // + if (forceBody) + { + // + isBullishDirection = + bar.GetUp() > hh && + bar.GetDown() > ll; + isBearishDirection = + bar.GetUp() < hh && + bar.GetDown() < ll; + result = isBullishDirection || + isBearishDirection; + if (!result) + { + return result; + } + } + + // + // Check Bar's Direction in related to CHOCH Direction ... + result = + isBullishDirection + ? bar.IsBullish() + : bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Set Direction ... + dir = + isBullishDirection + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Check Loopback End Bar ... + XOHCL endBar; + result = endBar.Init( + symbol, + period, + end - 1 // + ); + if (!result) + { + return result; + } + + // + // End Bar Must be InDirect by Specified Bar ... + result = + isBullishDirection + ? endBar.IsBearish() + : endBar.IsBullish(); + + // + // Check Loopback for Directional Bars ... + + // + return result; + } + + // + // Tools ... + + // + bool IsStrong( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetBody(); + + // + return result; + } + + // + bool HasStrongLowShadow( + XOHCL &bar, + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetLowShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = bar.Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = bar.Index() - __loopback; + int endIndex = bar.Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = bar.low == lowestLow && + highestHigh > bar.high; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = bar.Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = bar.Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = bar.GetLowShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + + // + bool HasStrongHighShadow( + XOHCL &bar, + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetHighShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = bar.Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = bar.Index() - __loopback; + int endIndex = bar.Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = bar.high == highestHigh && + lowestLow < bar.low; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = bar.Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = bar.Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = bar.GetHighShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + + // + bool IsStrongBullish( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = + bar.IsValid() && + bar.IsBullish() && + IsStrong(bar, percent); + + // + return result; + } + + // + bool IsStrongBearish( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = + bar.IsValid() && + bar.IsBearish() && + IsStrong(bar, percent); + + // + return result; + } + + // + bool IsSharpBullish( + XOHCL &bar, + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + int hIDX = bar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + int lIDX = bar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + result = + // + hIDX >= 0 && + lIDX >= 0 && + MathAbs(hIDX - bar.Index()) < 2 + // + ; + + // + if (!result) + { + return result; + } + + // + XOHCL hBar; + result = hBar.Init( + bar.symbol, + bar.period, + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL lBar; + result = lBar.Init( + bar.symbol, + bar.period, + lIDX // + ); + if (!result) + { + return result; + } + + // + double lhDif = hBar.high - lBar.low; + + // + int hhIDX = hBar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + + // + int llIDX = lBar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + XOHCL hhBar; + result = hhBar.Init( + bar.symbol, + bar.period, + hhIDX + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL llBar; + result = llBar.Init( + bar.symbol, + bar.period, + llIDX + lIDX // + ); + if (!result) + { + return result; + } + + // + double llhhDif = hhBar.high - llBar.low; + + // + result = + // + lBar.low > llBar.low && + hBar.high > hhBar.high && + lhDif >= llhhDif * _sharpRatio + // + ; + + // + return result; + } + + // + bool IsSharpBearish( + XOHCL &bar, + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + int hIDX = bar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + int lIDX = bar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + result = + // + hIDX >= 0 && + lIDX >= 0 && + MathAbs(hIDX - bar.Index()) < 2 + // + ; + + // + if (!result) + { + return result; + } + + // + XOHCL hBar; + result = hBar.Init( + bar.symbol, + bar.period, + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL lBar; + result = lBar.Init( + bar.symbol, + bar.period, + lIDX // + ); + if (!result) + { + return result; + } + + // + double lhDif = hBar.high - lBar.low; + + // + int hhIDX = hBar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + + // + int llIDX = lBar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + XOHCL hhBar; + result = hhBar.Init( + bar.symbol, + bar.period, + hhIDX + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL llBar; + result = llBar.Init( + bar.symbol, + bar.period, + llIDX + lIDX // + ); + if (!result) + { + return result; + } + + // + double llhhDif = hhBar.high - llBar.low; + + // + result = + // + lBar.low < llBar.low && + hBar.high < hhBar.high && + lhDif >= llhhDif * _sharpRatio + // + ; + + // + return result; + } + + // + // + // + + // + // Retrieve Bullish Pressure ... + double GetBullishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + result += bars[i].GetLowShadow(); + } + + // + return result; + } + + // + // Retrieve Bearish Pressure ... + double GetBearishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + result += bars[i].GetHighShadow(); + } + + // + return result; + } + + // + bool HasBullishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPressure(bar, __loopback); + double bearishPressure = GetBearishPressure(bar, __loopback); + + // + result = + // + bullishPressure > 0 && + bearishPressure >= 0 && + bullishPressure > bearishPressure + // + ; + + // + return result; + } + + // + bool HasBearishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPressure(bar, __loopback); + double bearishPressure = GetBearishPressure(bar, __loopback); + + // + result = + // + bearishPressure > 0 && + bullishPressure >= 0 && + bearishPressure > bullishPressure + // + ; + + // + return result; + } + + // + // Retrieve Bullish Power ... + double GetBullishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + // + if (bars[i].IsBullish()) + { + result += bars[i].GetBody(); + } + } + + // + return result; + } + + // + // Retrieve Bearish Pressure ... + double GetBearishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + // + if (bars[i].IsBearish()) + { + result += bars[i].GetBody(); + } + } + + // + return result; + } + + // + bool HasBullishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPower(bar, __loopback); + double bearishPressure = GetBearishPower(bar, __loopback); + + // + result = + // + bullishPressure > 0 && + bearishPressure >= 0 && + bullishPressure > bearishPressure + // + ; + + // + return result; + } + + // + bool HasBearishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPower(bar, __loopback); + double bearishPressure = GetBearishPower(bar, __loopback); + + // + result = + // + bearishPressure > 0 && + bullishPressure >= 0 && + bearishPressure > bullishPressure + // + ; + + // + return result; + } + + // + // Decisions ... + + // + bool IsBullishDecision( + XOHCL &bar, + double percent = 70 // Percent of Body + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + bar.Index() > 0 && + bar.IsBullish() && + (bar.GetRange() * percent) / 100 <= bar.GetBody() + // + ; + + // + return result; + } + + // + bool IsBearishDecision( + XOHCL &bar, + double percent = 70 // Percent of Body + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + bar.Index() > 0 && + bar.IsBearish() && + (bar.GetRange() * percent) / 100 <= bar.GetBody() + // + ; + + // + return result; + } + + // + // Candlestic Patterns ... + + // + // Check Doji ... + bool IsDoji( + XOHCL &bar // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.open == bar.close; + + // + return result; + } + + // + // Check Hammer ... + bool IsHammer( + XOHCL &bar, + double _upShadowFactor = 0.1, + double _downShadowFactor = 0.6, + bool applyFib382Check = true, + bool applyPrevShadowCheck = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_upShadowFactor < 0) + { + _upShadowFactor = 0.1; + } + + // + if (_downShadowFactor < 0) + { + _upShadowFactor = 0.6; + } + + // + double range = bar.GetRange(); + + // + // Check Upper Shadow Must be 0 or Under 10% ... + double upShadow = bar.GetHighShadow(); + result = upShadow < range * _upShadowFactor; + if (!result) + { + return result; + } + + // + // Check Down Shadow Must at least 60% ... + double downShadow = bar.GetLowShadow(); + result = downShadow > range * _downShadowFactor; + if (!result) + { + return result; + } + + // + // Check Fib 382 ... + if (result && applyFib382Check) + { + // + double fib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + -1 // + ); + result = bar.GetDown() > fib382; + } + + // + // Check Shadow Based on Prev Bar ... + if (result && applyPrevShadowCheck) + { + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + result = bar.low < pBar.low; + } + + // + return result; + } + + // + // Check Sgooting Star ... + // Reversal Hammer ... + bool IsShootingStar( + XOHCL &bar, + double _upShadowFactor = 0.6, + double _downShadowFactor = 0.1, + bool applyFib382Check = true, + bool applyPrevShadowCheck = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_upShadowFactor < 0) + { + _upShadowFactor = 0.6; + } + + // + if (_downShadowFactor < 0) + { + _upShadowFactor = 0.1; + } + + // + double range = bar.GetRange(); + + // + // Check Upper Shadow Must be 0 or Under 10% ... + double upShadow = bar.GetHighShadow(); + result = upShadow > range * _upShadowFactor; + if (!result) + { + return result; + } + + // + // Check Down Shadow Must at least 60% ... + double downShadow = bar.GetLowShadow(); + result = downShadow < range * _downShadowFactor; + if (!result) + { + return result; + } + + // + // Check Fib 382 ... + if (result && applyFib382Check) + { + // + double fib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + 1 // + ); + result = bar.GetUp() < fib382; + } + + // + // Check Shadow Based on Prev Bar ... + if (result && applyPrevShadowCheck) + { + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + result = bar.high > pBar.high; + } + + // + return result; + } + + // + // Check Bullish Engulfing ... + bool IsBullishEngulfing( + XOHCL &bar, + double _engulfBarBodyFactor = 0.7 // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_engulfBarBodyFactor < 0) + { + _engulfBarBodyFactor = 0.7; + } + + // + // Check Bar Is Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double body = bar.GetBody(); + + // + // Check Prev Bar Must Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Check Shadows Engulf Prev Bar ... + result = + // + bar.high > pBar.high && + bar.low <= pBar.low + // + ; + if (!result) + { + return result; + } + + // + // Check Engulfed Bar Must Inside Engulfer Body ... + result = + // + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown() + // + ; + if (!result) + { + return result; + } + + // + // Check Body of Engulfing Bar ... + if (result && _engulfBarBodyFactor > 0) + { + result = body >= range * _engulfBarBodyFactor; + } + + // + return result; + } + + // + // Check Bearish Engulfing ... + bool IsBearishEngulfing( + XOHCL &bar, + double _engulfBarBodyFactor = 0.7 // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_engulfBarBodyFactor < 0) + { + _engulfBarBodyFactor = 0.7; + } + + // + // Check Bar Is Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double body = bar.GetBody(); + + // + // Check Prev Bar Must Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Check Shadows Engulf Prev Bar ... + result = bar.high >= pBar.high && + bar.low < pBar.low; + if (!result) + { + return result; + } + + // + // Check Engulfed Bar Must Inside Engulfer Body ... + result = + // + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown() + // + ; + if (!result) + { + return result; + } + + // + // Check Body of Engulfing Bar ... + if (result && _engulfBarBodyFactor > 0) + { + result = body >= range * _engulfBarBodyFactor; + } + + // + return result; + } + + // + // Check Morning Star Pattern ... + bool IsMorningStar( + XOHCL &bar, + double _middleRangeFactor = 0.3, + double _startBodyFactor = 0.6, + bool forceCheckMiddleBarDirection = true, + bool forceCheckStartBody = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_middleRangeFactor < 0) + { + _middleRangeFactor = 0.3; + } + + // + if (_startBodyFactor < 0) + { + _startBodyFactor = 0.6; + } + + // + // Current Bar Must be Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar must be Bearish ... + if (result && forceCheckMiddleBarDirection) + { + // + result = pBar.IsBearish(); + if (!result) + { + return result; + } + } + + // + // Retrieve Previous Bar of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev Of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double pRange = pBar.GetRange(); + double ppRange = ppBar.GetRange(); + + // + // Middle Bar must be Smaller than Ratio of other ... + result = + // + pRange < range * _middleRangeFactor && + pRange < ppRange * _middleRangeFactor + // + ; + if (!result) + { + return result; + } + + // + if (result && forceCheckStartBody) + { + // + result = ppBar.GetBody() > ppRange * _startBodyFactor; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Check Evening Star Pattern ... + bool IsEveningStar( + XOHCL &bar, + double _middleRangeFactor = 0.3, + double _startBodyFactor = 0.6, + bool forceCheckMiddleBarDirection = true, + bool forceCheckStartBody = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_middleRangeFactor < 0) + { + _middleRangeFactor = 0.3; + } + + // + if (_startBodyFactor < 0) + { + _startBodyFactor = 0.6; + } + + // + // Current Bar Must be Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar must be Bullish ... + if (result && forceCheckMiddleBarDirection) + { + // + result = pBar.IsBullish(); + if (!result) + { + return result; + } + } + + // + // Retrieve Previous Bar of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev Of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double pRange = pBar.GetRange(); + double ppRange = ppBar.GetRange(); + + // + // Middle Bar must be Smaller than Ratio of other ... + result = + // + pRange < range * _middleRangeFactor && + pRange < ppRange * _middleRangeFactor + // + ; + if (!result) + { + return result; + } + + // + if (result && forceCheckStartBody) + { + // + result = ppBar.GetBody() > ppRange * _startBodyFactor; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Bullish Marubozu ... + bool IsBullishMarubozu(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + result = + // + bar.GetUp() == bar.high && + bar.GetDown() == bar.low + // + ; + + // + return result; + } + + // + // Bearish Marubozu ... + bool IsBearishMarubozu(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + result = + // + bar.GetUp() == bar.high && + bar.GetDown() == bar.low + // + ; + + // + return result; + } + + // + // Contextual Patterns ... + + // + // Check Swing High ... + bool IsBarSwingHigh(XOHCL &bar) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Check All Highs ... + result = + // + bar.high < pBar.high && + pBar.high > ppBar.high + // + ; + + // + return result; + } + + // + // Find Simple 3 Candle Based Swing High ... + bool IsSimpleSwingHigh( + XOHCL &bar, + double thresholdInPoint = 1 // + ) + { + // + bool result = false; + + // + int index = bar.Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = bar.GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = bar.GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(bar.symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + bar.high > nextBar.high && + bar.high > prevBar.high && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.high, + prevBar.high) - + bar.high) >= requiredOffset); + + // + return result; + } + + // + // Find Last Swing High ... + bool FindLastSwingHigh( + XOHCL &bar, + XOHCL &swing // + ) + { + // + bool result = false; + + // + swing.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = iBars( + bar.symbol, + bar.period // + ); + int maxAllowed = MathMin(100, (totalBars / 100)); + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + maxAllowed; i++) + { + // + swing.Clean(); + result = swing.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + // + swing.Clean(); + break; + } + + // + result = IsBarSwingHigh(swing); + if (result) + { + break; + } + } + + // + return result; + } + + // + // Check Swing Low ... + bool IsBarSwingLow(XOHCL &bar) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Check All Lows ... + result = + // + bar.low > pBar.low && + pBar.low < ppBar.low + // + ; + + // + return result; + } + + // + // Find Simple 3 Candle Based Swing Low ... + bool IsSimpleSwingLow( + XOHCL &bar, + double thresholdInPoint = 1 // + ) + { + // + bool result = false; + + // + int index = bar.Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = bar.GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = bar.GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(bar.symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + bar.low < nextBar.low && + bar.low < prevBar.low && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.low, + prevBar.low) - + bar.low) >= requiredOffset); + + // + return result; + } + + // + // Find Last Swing Low ... + bool FindLastSwingLow( + XOHCL &bar, + XOHCL &swing // + ) + { + // + bool result = false; + + // + swing.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = iBars( + bar.symbol, + bar.period // + ); + int maxAllowed = MathMin(100, (totalBars / 100)); + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + maxAllowed; i++) + { + // + swing.Clean(); + result = swing.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + // + swing.Clean(); + break; + } + + // + result = IsBarSwingLow(swing); + if (result) + { + break; + } + } + + // + return result; + } + + // + // Check Bullish FVG ... + bool HasBullishFVG( + XOHCL &bar, + double &upper, + double &lower, + datetime &start, + datetime &end, + bool forceMiddleBarCheck = true, + bool forceCheckLastBarDirection = false // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + end = NULL; + start = NULL; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bullish ... + result = + !forceCheckLastBarDirection + ? true + : bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Other Conditions ... + result = + // + bar.low > ppBar.high + // + ; + + // + // Check Middle Bar Range ... + if (result && forceMiddleBarCheck) + { + // + result = + // + pBar.high > bar.low && + pBar.low < ppBar.high + // + ; + + // + if (!result) + { + return result; + } + } + + // + if (result) + { + // + end = bar.time; + upper = bar.low; + lower = ppBar.high; + start = ppBar.time; + } + + // + return result; + } + + // + // Check Bearish FVG ... + bool HasBearishFVG( + XOHCL &bar, + double &upper, + double &lower, + datetime &start, + datetime &end, + bool forceMiddleBarCheck = true, + bool forceCheckLastBarDirection = false // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + end = NULL; + start = NULL; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bearish ... + result = + !forceCheckLastBarDirection + ? true + : bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Other Conditions ... + result = + // + bar.high < ppBar.low + // + ; + + // + // Check Middle Bar Range ... + if (result && forceMiddleBarCheck) + { + // + result = + // + pBar.high > bar.low && + pBar.low < ppBar.high + // + ; + + // + if (!result) + { + return result; + } + } + + // + if (result) + { + // + end = bar.time; + lower = bar.high; + upper = ppBar.low; + start = ppBar.time; + } + + // + return result; + } + + // + // Find Support ... + bool HasSupport( + XOHCL &bar, + XOHCL &dest, + ENUM_X_PRICE type = X_PRICE_CLOSE, + int _loopback = 21, + int tries = 100 // + ) + { + // + bool result = false; + + // + dest.Clean(); + + // + if (_loopback < 0) + { + _loopback = 21; + } + + // + if (tries < 0) + { + tries = 100; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + for (int i = 1; i < tries; i++) + { + // + int _length = _loopback * i; + + // + int lowestIDX = bar.FindLowestIndex( + _length, + MODE_LOW // + ); + result = IsValidIndex(lowestIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + lowestIDX // + ); + if (!result) + { + break; + } + + // + result = + // + price > iLBar.high + // + ; + if (result) + { + // + dest = iLBar; + break; + } + } + + // + result = dest.IsValid(); + + // + return result; + } + + // + // Find Resistance ... + bool HasResistance( + XOHCL &bar, + XOHCL &dest, + ENUM_X_PRICE type = X_PRICE_CLOSE, + int _loopback = 21, + int tries = 100 // + ) + { + // + bool result = false; + + // + dest.Clean(); + + // + if (_loopback < 0) + { + _loopback = 21; + } + + // + if (tries < 0) + { + tries = 100; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + for (int i = 1; i < tries; i++) + { + // + int _length = _loopback * i; + + // + int highestIDX = bar.FindHighestIndex( + _length, + MODE_LOW // + ); + result = IsValidIndex(highestIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + highestIDX // + ); + if (!result) + { + break; + } + + // + result = + // + price < iHBar.high + // + ; + if (result) + { + // + dest = iHBar; + break; + } + } + + // + result = dest.IsValid(); + + // + return result; + } + + // + // Trend Detection ... + + // + // Find Bullish Trend ... + bool HasBullishTrend( + XOHCL &bar, + XOHCL &highSwingBars[], + XOHCL &lowSwingBars[], + bool forceMethod2 = false, + int _loopback = 3, + int tries = 3, + ENUM_X_PRICE type = X_PRICE_CLOSE // + ) + { + // + bool result = false; + + // + Clean(lowSwingBars); + Clean(highSwingBars); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + int lastIDX = bar.Index(); + double lastH = 0; + double lastL = 0; + for (int i = 1; i < tries + 1; i++) + { + // + // Use Regular Method ... + if (!forceMethod2) + { + // + int iHIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_HIGH, + _loopback, + lastIDX // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH < lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_LOW, + _loopback, + lastIDX // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL < lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + // + // Use Other MEthod ... + else + { + // + int _length = i * _loopback; + int start = + // + i == 1 + ? 1 + : _length - _loopback + // + ; + + // + int iHIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + _loopback, + start // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH < lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + _loopback, + start // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL < lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + } + + // + if (result) + { + // + result = + // + ArraySize(lowSwingBars) == tries && + ArraySize(highSwingBars) == tries + // + ; + } + + // + if (!result) + { + // + Clean(lowSwingBars); + Clean(highSwingBars); + } + + // + return result; + } + + // + // Find Bearish Trend ... + bool HasBearishTrend( + XOHCL &bar, + XOHCL &highSwingBars[], + XOHCL &lowSwingBars[], + bool forceMethod2 = false, + int _loopback = 3, + int tries = 3, + ENUM_X_PRICE type = X_PRICE_CLOSE // + ) + { + // + bool result = false; + + // + Clean(lowSwingBars); + Clean(highSwingBars); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + int lastIDX = bar.Index(); + double lastH = 0; + double lastL = 0; + for (int i = 1; i < tries + 1; i++) + { + // + // Use Regular Method ... + if (!forceMethod2) + { + // + int iHIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_HIGH, + _loopback, + lastIDX // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH > lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_LOW, + _loopback, + lastIDX // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL > lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + // + // Use Other MEthod ... + else + { + // + int _length = i * _loopback; + int start = + // + i == 1 + ? 1 + : _length - _loopback + // + ; + + // + int iHIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + _loopback, + start // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH > lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + _loopback, + start // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL > lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + } + + // + if (result) + { + // + result = + // + ArraySize(lowSwingBars) == tries && + ArraySize(highSwingBars) == tries + // + ; + } + + // + if (!result) + { + // + Clean(lowSwingBars); + Clean(highSwingBars); + } + + // + return result; + } + + // + // Order Blocks ... + + // + // Find Bullish Order Block ... + bool HasBullishOrderBlock( + XOHCL &bar, + XOHCL &orderBlock, + int _minimumSameBars = 4 // + ) + { + // + bool result = false; + + // + orderBlock.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (_minimumSameBars < 0) + { + _minimumSameBars = 4; + } + + // + XOHCL cBar; + int founded = 0; + int cIDX = bar.Index(); + bool isEnough = false; + while (!isEnough) + { + // + result = cBar.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + break; + } + + // + result = cBar.IsBullish(); + if (!result && cBar.IsBearish()) + { + break; + } + + // + cIDX++; + founded++; + } + + // + // Here we have to check founded and if it's fill + // our requirements ... + // cIDX is Order Block Index ... + result = + // + cBar.IsValid() && + bar.high > cBar.high && + founded >= _minimumSameBars + // + ; + if (!result) + { + return result; + } + + // + result = orderBlock.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + // + orderBlock.Clean(); + return result; + } + + // + return result; + } + + // + // Find Bearish Order Block ... + bool HasBearishOrderBlock( + XOHCL &bar, + XOHCL &orderBlock, + int _minimumSameBars = 4 // + ) + { + // + bool result = false; + + // + orderBlock.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (_minimumSameBars < 0) + { + _minimumSameBars = 4; + } + + // + XOHCL cBar; + int founded = 0; + int cIDX = bar.Index(); + bool isEnough = false; + while (!isEnough) + { + // + bool isInited = cBar.Init( + bar.symbol, + bar.period, + cIDX // + ); + + // + result = cBar.IsBearish(); + if (!result && cBar.IsBullish()) + { + break; + } + + // + cIDX++; + founded++; + } + + // + // Here we have to check founded and if it's fill + // our requirements ... + // cIDX is Order Block Index ... + result = + // + cBar.IsValid() && + bar.high < cBar.low && + founded >= _minimumSameBars + // + ; + if (!result) + { + return result; + } + + // + result = orderBlock.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + // + orderBlock.Clean(); + return result; + } + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + // Props ... + + // + // Actions ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-cobject.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-cobject.class.mq5 new file mode 100644 index 0000000..2666968 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-cobject.class.mq5 @@ -0,0 +1,3878 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +#include +#include +#include +#include +#include +#include + +// +// Definitions ... + +enum ENUM_XCHARTOBJECTS +{ + // + // Global ... + X_ZONE_OBJ = 7860, + X_BOX_OBJ = 7861, + X_BAR_ARROW_OBJ = 7862, + // + X_SIGNAL_OBJ = 8860, + X_TREND_OBJ = 8861, + X_XPVPIVOT_OBJ = 8862, + X_OHCL_OBJ = 8863, + X_RR_OBJ = 8864, + // + // Structured ... + X_TRADE_DAY_OBJ = 9860, + X_MARKET_SESSION_OBJ = 9861, + X_SWING_HIGH_OBJ = 9862, + X_SWING_LOW_OBJ = 9863, + X_BULLISH_MOMENTUM_BAR_OBJ = 9864, + X_BEARISH_MOMENTUM_BAR_OBJ = 9865, + X_BULLISH_REJECTION_BAR_OBJ = 9866, + X_BEARISH_REJECTION_BAR_OBJ = 9867, + X_SUPPORT_ZONE_OBJ = 9868, + X_RESISTANCE_ZONE_OBJ = 9869, + X_SUPPLY_ZONE_OBJ = 9870, + X_DEMAND_ZONE_OBJ = 9871, + X_BULLISH_ORDERBLOCK_OBJ = 9872, + X_BEARISH_ORDERBLOCK_OBJ = 9873, + X_BULLISH_FVG_OBJ = 9874, + X_BEARISH_FVG_OBJ = 9875, + X_TICK_ZONE_OBJ = 9876, + X_TICKS_ZONE_OBJ = 9877, + X_CONSOLIDATION_ZONE_OBJ = 9878, +}; + +enum ENUM_X_CHART_IDS +{ + X_TO, + X_FROM, + X_UPPER, + X_LOWER, + X_ENTRY, + X_TARGET, + X_SL, + X_TP, + X_BAR_H_SHW, + X_BAR_BDY, + X_BAR_L_SHW, +}; + +string ToString(ENUM_X_CHART_IDS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_TO: + result = "TO"; + break; + + // + case X_FROM: + result = "FROM"; + break; + + // + case X_UPPER: + result = "UPPER"; + break; + + // + case X_LOWER: + result = "LOWER"; + break; + + // + case X_ENTRY: + result = "ENTRY"; + break; + + // + case X_TARGET: + result = "TARGET"; + break; + + // + case X_SL: + result = "SL"; + break; + + // + case X_TP: + result = "TP"; + break; + + // + case X_BAR_H_SHW: + result = "HSHW"; + break; + + // + case X_BAR_BDY: + result = "BODY"; + break; + + // + case X_BAR_L_SHW: + result = "LSHW"; + break; + + // + } + + // + return result; +} + +// +// Implementation ... + +// +// Global Chart Objects ... + +// +// Bas Chart Object ... +class XCBaseObject : public CChartObject +{ + // + public: + // + + // + // Getter(s) / Setter(s) ... + + /** + * Get Object Specified Name ... + * + * @return ( string ) + */ + string ObjName() + { + return mObjName; + } + + /** + * Set Object Specified Name ... + * + * @param value: String ... + */ + void ObjName(string value) + { + mObjName = value; + } + + // + private: + // + + // + // Props ... + string mObjName; // Object Specified Name ... + + // +}; + +class XCBarArrowObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param name: String, Specified Object ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param swing: XCSwing instance ... + * + * @return ( bool ) + */ + bool CreateByBar( + long chart_id, + string name, + int window, + int arrow, + XOHCL &bar, + ENUM_X_PRICE priceType // + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + IsValid(name) + // + ; + if (!result) + { + return result; + } + + // + datetime time = bar.time; + double price = bar.GetPrice(priceType); + + // + result = mArrow.Create( + chart_id, + name, + window, + time, + price, + (char)arrow // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + // + // Setter(s) ... + + /** + * Set Arrow Anchor ... + * + * @param value: ENUM_ARROW_ANCHOR member ... + */ + void ArrowAnchor(ENUM_ARROW_ANCHOR value) + { + mArrow.Anchor(value); + } + + /** + * Set Arrow Color ... + * + * @param value: Color ... + */ + void ArrowColor(color value) + { + mArrow.Color(value); + } + + /** + * Set Arrow Width ... + * + * @param value: Integer ... + */ + void ArrowWidth(int value) + { + mArrow.Width(value); + } + + // + private: + // + CChartObjectArrow mArrow; + + // +}; + +// +// Swing ... +class XCSwingObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateBySwing( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + swing.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = swing.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = swing.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = swing.IsSwingHigh() + ? X_PRICE_HIGH + : X_PRICE_LOW; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Swing High ... +class XCSwingHighObject : public XCSwingObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = swing.IsValid() && + swing.IsSwingHigh(); + if (!result) + { + return result; + } + + // + result = CreateBySwing( + chart_id, + window, + arrow, + swing, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SWING_HIGH_OBJ; + } + + // +}; + +// +// Swing Low ... +class XCSwingLowObject : public XCSwingObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = swing.IsValid() && + swing.IsSwingLow(); + if (!result) + { + return result; + } + + // + result = CreateBySwing( + chart_id, + window, + arrow, + swing, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SWING_LOW_OBJ; + } + + // +}; + +// +// Momentum ... +class XCMomentumBarObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByMomentum( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + momentumBar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = momentumBar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = momentumBar.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = momentumBar.IsBullish() + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Bullish Momentum Bar ... +class XCBullishMomentumBarObject : public XCMomentumBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = momentumBar.IsValid() && + momentumBar.IsBullish(); + if (!result) + { + return result; + } + + // + result = CreateByMomentum( + chart_id, + window, + arrow, + momentumBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_MOMENTUM_BAR_OBJ; + } + + // +}; + +// +// Bearish Momentum Bar ... +class XCBearishMomentumBarObject : public XCMomentumBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = momentumBar.IsValid() && + momentumBar.IsBearish(); + if (!result) + { + return result; + } + + // + result = CreateByMomentum( + chart_id, + window, + arrow, + momentumBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_MOMENTUM_BAR_OBJ; + } + + // +}; + +// +// Rejection ... +class XCRejectionBarObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByRejection( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + rejectionBar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = rejectionBar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = rejectionBar.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = rejectionBar.IsBullish() + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Bullish Rejection Bar ... +class XCBullishRejectionBarObject : public XCRejectionBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = rejectionBar.IsValid() && + rejectionBar.IsBullish(); + if (!result) + { + return result; + } + + // + result = CreateByRejection( + chart_id, + window, + arrow, + rejectionBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_REJECTION_BAR_OBJ; + } + + // +}; + +// +// Bearish Rejection Bar ... +class XCBearishRejectionBarObject : public XCRejectionBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = rejectionBar.IsValid() && + rejectionBar.IsBearish(); + if (!result) + { + return result; + } + + // + result = CreateByRejection( + chart_id, + window, + arrow, + rejectionBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_REJECTION_BAR_OBJ; + } + + // +}; + +// +// XCZoneObject ... +class XCZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param name: String, Specified Object Identifier on Chart ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByZone( + long chart_id, + string name, + int window, + XCZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + bool isValidFrom = zone.IsValidFrom(); + bool isValidBoundary = zone.IsValidBoundary(); + + // + result = + // + IsValid(name) && + isValidFrom && + isValidBoundary + // + ; + if (!result) + { + return result; + } + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + datetime from = zone.From(); + datetime to = NormalizeTime(zone.To()); + + // + double upper = zone.Upper(); + double lower = zone.Lower(); + + // + result = mRect.Create( + chart_id, + name, + window, + from, + upper, + to, + lower // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_ZONE_OBJ; + } + + // + // Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + // + private: + // + CChartObjectRectangle mRect; + + // +}; + +// +// Support Zone ... +class XCSupportZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCSupportZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCSupportZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SUPPORT_ZONE_OBJ; + } +}; + +// +// Resistance Zone ... +class XCResistanceZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCResistanceZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCResistanceZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_RESISTANCE_ZONE_OBJ; + } +}; + +// +// Supply Zone ... +class XCSupplyZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCSupplyZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCSupplyZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SUPPLY_ZONE_OBJ; + } +}; + +// +// Demand Zone ... +class XCDemandZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCDemandZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCDemandZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_DEMAND_ZONE_OBJ; + } +}; + +// +// Bullish Order Block ... +class XCBullishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; + } +}; + +// +// Bearish Order Block ... +class XCBearishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; + } +}; + +// +// Bullish Fair Value Gaps ... +class XCBullishFairValueGapObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCFVG &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_FVG_OBJ; + } +}; + +class XCConsolidationZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XConsolidationZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XConsolidationZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + result = mRect.Create( + chart_id, + name, + window, + zone.from, + zone.upper, + zone.to, + zone.lower // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_CONSOLIDATION_ZONE_OBJ; + } + + // + // Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + // + private: + // + CChartObjectRectangle mRect; + + // +}; + +// +// Bearish Fair Value Gaps ... +class XCBearishFairValueGapObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCFVG &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_FVG_OBJ; + } +}; + +// +// Signal ... +class XCSignalObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + void XCSignalObject() + { + } + + // + // Deconstructor ... + void ~XCSignalObject() + { + } + + /** + * Create a Signal Object on Chart ... + * + * @param chart_id: Long ... + * @param name: String ... + * @param window: Integer ... + * @param signal: XSignal instance ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + const int window, + XSignal &signal, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string name = signal.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + int delay = (PeriodSeconds(signal.period) * 2); + datetime time1 = (datetime)((int)signal.time - delay); + datetime time2 = (datetime)((int)signal.time + delay); + + // + // TP ... + string tpName = ToString(X_TP) + "_" + nameMD5; + result = mTPTrend.Create( + chart_id, + tpName, + window, + time1, + signal.tp, + time2, + signal.tp // + ); + if (!result) + { + return result; + } + + // + // SL ... + string slName = ToString(X_SL) + "_" + nameMD5; + result = mSLTrend.Create( + chart_id, + slName, + window, + time1, + signal.sl, + time2, + signal.sl // + ); + if (!result) + { + // + mTPTrend.Delete(); + return result; + } + + // + // TARGET ... + bool hasTargets = HasChild(signal.targets); + if (hasTargets) + { + // + int targetsCount = ArraySize(signal.targets); + for (int i = 0; i < targetsCount; i++) + { + // + string targetName = ToString(X_TARGET) + "_" + ToString(i) + "_" + nameMD5; + CChartObjectTrend *mTargetTrend; + mTargetTrend = new CChartObjectTrend(); + result = mTargetTrend.Create( + chart_id, + targetName, + window, + time1, + signal.targets[i], + time2, + signal.targets[i] // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + break; + } + + // + mTargetTrends.Add(mTargetTrend); + } + } + + // + // ENTRY ... + string entrName = ToString(X_ENTRY) + "_" + nameMD5; + result = mEntryTrend.Create( + chart_id, + entrName, + window, + time1, + signal.entry, + time2, + signal.entry // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + mTargetTrends.Clear(); + return result; + } + + // + // Set Object Name ... + ObjName(name); + + // + return result; + } + + // + // Setter(s) ... + + // + // TP ... + + /** + * Set TP Width ... + * + * @param value: Integer ... + */ + void TPWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mTPTrend.Width(value); + } + + /** + * Set TP Color ... + * + * @param value: Color ... + */ + void TPColor(color value) + { + mTPTrend.Color(value); + } + + /** + * Set TP Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TPStyle(ENUM_LINE_STYLE value) + { + mTPTrend.Style(value); + } + + // + // SL ... + + /** + * Set SL Width ... + * + * @param value: Integer ... + */ + void SLWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSLTrend.Width(value); + } + + /** + * Set SL Color ... + * + * @param value: Color ... + */ + void SLColor(color value) + { + mSLTrend.Color(value); + } + + /** + * Set SL Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void SLStyle(ENUM_LINE_STYLE value) + { + mSLTrend.Style(value); + } + + // + // TARGET ... + + /** + * Set Target Width ... + * + * @param value: Integer ... + */ + void TargetWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Width(value); + } + } + + /** + * Set Target Color ... + * + * @param value: Color ... + */ + void TargetColor(color value) + { + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Color(value); + } + } + + /** + * Set Target Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TargetStyle(ENUM_LINE_STYLE value) + { + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Style(value); + } + } + + // + // ENTRY ... + + /** + * Set Entry Width ... + * + * @param value: Integer ... + */ + void EntryWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mEntryTrend.Width(value); + } + + /** + * Set Entry Color ... + * + * @param value: Color ... + */ + void EntryColor(color value) + { + mEntryTrend.Color(value); + } + + /** + * Set Entry Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void EntryStyle(ENUM_LINE_STYLE value) + { + mEntryTrend.Style(value); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SIGNAL_OBJ; + } + + // + private: + // + + // + CChartObjectTrend mTPTrend; + CChartObjectTrend mSLTrend; + CChartObjectTrend mEntryTrend; + CArrayObj mTargetTrends; +}; + +class XCOHCLObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XOHCL &bar, + datetime to, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + IsValid(to); + if (!result) + { + return result; + } + + // + string name = bar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + // High Shadow ... + string hShadowName = ToString(X_BAR_H_SHW) + "_" + nameMD5; + + // + result = mHighShadowRect.Create( + chart_id, + hShadowName, + window, + bar.time, + bar.high, + to, + bar.GetUp() // + ); + if (!result) + { + return result; + } + + // + // Body ... + string bodyName = ToString(X_BAR_BDY) + "_" + nameMD5; + + // + result = mBodyRect.Create( + chart_id, + bodyName, + window, + bar.time, + bar.GetUp(), + to, + bar.GetDown() // + ); + if (!result) + { + // + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + // Low Shadow ... + string lShadowName = ToString(X_BAR_L_SHW) + "_" + nameMD5; + + // + result = mLowShadowRect.Create( + chart_id, + lShadowName, + window, + bar.time, + bar.GetDown(), + to, + bar.low // + ); + if (!result) + { + // + mBodyRect.Delete(); + mBodyRect.Detach(); + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set High Shadow Width ... + * + * @param value: Integer ... + */ + void HighShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mHighShadowRect.Width(value); + } + + /** + * Set High Shadow Color ... + * + * @param value: Color ... + */ + void HighShadowColor(color value) + { + mHighShadowRect.Color(value); + } + + /** + * Set High Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void HighShadowStyle(ENUM_LINE_STYLE value) + { + mHighShadowRect.Style(value); + } + + /** + * Set High Shadow Fill ... + * + * @param value: Boolean ... + */ + void HighShadowFill(bool value) + { + mHighShadowRect.Fill(value); + } + + /** + * Set Body Width ... + * + * @param value: Integer ... + */ + void BodyWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBodyRect.Width(value); + } + + /** + * Set Body Color ... + * + * @param value: Color ... + */ + void BodyColor(color value) + { + mBodyRect.Color(value); + } + + /** + * Set Body Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BodyStyle(ENUM_LINE_STYLE value) + { + mBodyRect.Style(value); + } + + /** + * Set Body Fill ... + * + * @param value: Boolean ... + */ + void BodyFill(bool value) + { + mBodyRect.Fill(value); + } + + /** + * Set Low Shadow Width ... + * + * @param value: Integer ... + */ + void LowShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mLowShadowRect.Width(value); + } + + /** + * Set Low Shadow Color ... + * + * @param value: Color ... + */ + void LowShadowColor(color value) + { + mLowShadowRect.Color(value); + } + + /** + * Set Low Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void LowShadowStyle(ENUM_LINE_STYLE value) + { + mLowShadowRect.Style(value); + } + + /** + * Set Low Shadow Fill ... + * + * @param value: Boolean ... + */ + void LowShadowFill(bool value) + { + mLowShadowRect.Fill(value); + } + + void BarSpes( + int width = 1, + color clr = clrNONE, + ENUM_LINE_STYLE style = STYLE_SOLID, + bool fill = false // + ) + { + // + BodyWidth(width); + LowShadowWidth(width); + HighShadowWidth(width); + + // + BodyColor(clr); + LowShadowColor(clr); + HighShadowColor(clr); + + // + BodyStyle(style); + LowShadowStyle(style); + HighShadowStyle(style); + + // + BodyFill(fill); + LowShadowFill(fill); + HighShadowFill(fill); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_OHCL_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mHighShadowRect; + CChartObjectRectangle mBodyRect; + CChartObjectRectangle mLowShadowRect; +}; + +class XCBoxObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + string name, + double upper, + double lower, + datetime from, + datetime to, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + upper > 0 && + lower > 0 && + to > from && + IsValid(to) && + IsValid(name) && + IsValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + result = mRect.Create( + chart_id, + name, + window, + from, + upper, + to, + lower // + ); + if (!result) + { + return result; + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Width ... + * + * @param value: Integer ... + */ + void BoxWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Color ... + * + * @param value: Color ... + */ + void BoxColor(color value) + { + mRect.Color(value); + } + + /** + * Set Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BoxStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Fill ... + * + * @param value: Boolean ... + */ + void BoxFill(bool value) + { + mRect.Fill(value); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BOX_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mRect; +}; + +class XCRRObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param rr: XRR instance Reference ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XRR &rr, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = rr.IsValid(); + if (!result) + { + return result; + } + + // + string name = rr.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + bool isLong = IsLong(rr.type); + + // + double price1 = rr.entry; + double price2 = rr.sl; + + // + datetime time1 = rr.time; + datetime time2 = (datetime)((int)rr.time + 5 * PeriodSeconds(rr.period)); + + // + result = mFibo.Create( + chart_id, + name, + window, + time1, + price1, + time2, + price2 // + ); + if (!result) + { + return result; + } + + // + mRR = rr; + ObjName(name); + + // + int tpsCount = ArraySize(rr.tps); + int levels = tpsCount + 2; + result = mFibo.LevelsCount(levels); + if (!result) + { + return result; + } + + // + // Set Fibo Levels ... + + // + result = mFibo.LevelValue(0, 0); + if (!result) + { + return result; + } + result = mFibo.LevelDescription(0, "SL"); + if (!result) + { + return result; + } + + // + result = mFibo.LevelValue(1, 1.0); + if (!result) + { + return result; + } + result = mFibo.LevelDescription(1, "Entry"); + if (!result) + { + return result; + } + + // + for (int i = 0; i < tpsCount; i++) + { + // + int idx = i + 2; + double level = 1.0 + rr.tps[i]; + string description = "TP " + ToString(rr.tps[i]); + + // + result = mFibo.LevelValue( + idx, + level // + ); + if (!result) + { + break; + } + + // + result = mFibo.LevelDescription( + idx, + description // + ); + if (!result) + { + break; + } + } + if (!result) + { + return result; + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_RR_OBJ; + } + + // + private: + // + + // + // Props ... + XRR mRR; + CChartObjectFibo mFibo; + + // + bool SetSLProps( + int width = 1, + color clr = clrRed, + ENUM_LINE_STYLE style = STYLE_SOLID, + string description = "" // + ) + { + // + bool result = false; + + // + result = SetLevelProps( + 0, + width, + clr, + style, + description // + ); + + // + return result; + } + + // + bool SetEntryProps( + int width = 1, + color clr = clrOrange, + ENUM_LINE_STYLE style = STYLE_SOLID, + string description = "" // + ) + { + // + bool result = false; + + // + result = SetLevelProps( + 0, + width, + clr, + style, + description // + ); + + // + return result; + } + + // + bool SetTPProps( + double tpValue, + int width = 1, + color clr = clrLime, + ENUM_LINE_STYLE style = STYLE_SOLID, + string description = "" // + ) + { + // + bool result = false; + + // + int tpIDX = FindIndex( + tpValue, + mRR.tps // + ); + result = IsValidIndex(tpIDX); + if (!result) + { + return result; + } + + // + tpIDX += 2; + + // + result = SetLevelProps( + tpIDX, + width, + clr, + style, + description // + ); + + // + return result; + } + + // + bool SetLevelProps( + int id, + int width = 1, + color clr = clrYellow, + ENUM_LINE_STYLE style = STYLE_SOLID, + string description = "" // + ) + { + // + bool result = false; + + // + // Color ... + result = mFibo.LevelColor( + id, + clr // + ); + if (!result) + { + return result; + } + + // + // Style ... + result = mFibo.LevelStyle( + id, + style // + ); + if (!result) + { + return result; + } + + // + // Width ... + if (width > 0) + { + // + result = mFibo.LevelWidth( + id, + width // + ); + if (!result) + { + return result; + } + } + + // + // Description ... + if (IsValid(description)) + { + // + result = mFibo.LevelDescription( + id, + description // + ); + if (!result) + { + return result; + } + } + + // + return result; + } +}; + +class XCTrendObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param rr: XRR instance Reference ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XPoint &swings[], + bool useMinAsStart = true, + string prefix = NULL // + ) + { + // + bool result = false; + + // + int count = ArraySize(swings); + result = + count >= 2 && + IsValidSize(count); + if (!result) + { + return result; + } + + // + double min = 0; + datetime minAt = NULL; + + // + double max = 0; + datetime maxAt = NULL; + + // + // Etract Min/Max ... + for (int i = 0; i < count; i++) + { + // + XPoint iPoint = swings[i]; + + // + if (!iPoint.IsValid()) + { + // + iPoint.Clean(); + continue; + } + + // + bool canSetMin = + min == 0 + ? true + : min > iPoint.value; + if (canSetMin) + { + // + minAt = iPoint.at; + min = iPoint.value; + } + + // + bool canSetMax = + max == 0 + ? true + : max < iPoint.value; + if (canSetMax) + { + // + maxAt = iPoint.at; + max = iPoint.value; + } + + // + iPoint.Clean(); + } + + // + double first = + useMinAsStart + ? min + : max; + datetime firstTime = + useMinAsStart + ? minAt + : maxAt; + + // + double second = + useMinAsStart + ? max + : min; + datetime secondTime = + useMinAsStart + ? maxAt + : minAt; + + // + // Validate Points ... + result = + // + first > 0 && + second > 0 && + (useMinAsStart + ? first <= second + : first >= second) && + IsSpecifiedValid(firstTime) && + IsSpecifiedValid(secondTime) + // + ; + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION dir = + useMinAsStart + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + string name = "XTRND" + ToString(dir) + "_" + ToString(first) + "_" + ToString(second); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + result = mTrend.Create( + chart_id, + name, + window, + firstTime, + first, + secondTime, + second // + ); + if (!result) + { + return result; + } + + // + ObjName(name); + + // + return result; + } + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param rr: XRR instance Reference ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XSwingPoint &swings[], + string prefix = NULL // + ) + { + // + bool result = false; + + // + int count = ArraySize(swings); + result = + count >= 2 && + IsValidSize(count); + if (!result) + { + return result; + } + + // + ENUM_X_SWING_TYPE type = swings[0].type; + bool isSwingLows = type == X_SWING_LOW; + + // + double values[]; + int valuesCount = ExtractSwings( + swings, + values // + ); + result = valuesCount == count; + if (!result) + { + return result; + } + + // + int firstIDX = -1; + double first = 0; + datetime firstTime = NULL; + + // + int secondIDX = -1; + double second = 0; + datetime secondTime = NULL; + + // + if (isSwingLows) + { + // + first = GetMin( + values, + firstIDX, + 0, + 0 // + ); + if (IsValidIndex(firstIDX)) + { + // + firstTime = swings[firstIDX].time; + + // + second = FindBiggerThan( + first, + values, + true // + ); + secondIDX = FindIndex( + second, + values // + ); + if (IsValidIndex(secondIDX)) + { + secondTime = swings[secondIDX].time; + } + } + } + else + { + // + first = GetMax( + values, + firstIDX, + 0, + 0 // + ); + if (IsValidIndex(firstIDX)) + { + // + firstTime = swings[firstIDX].time; + + // + second = FindLesserThan( + first, + values, + true // + ); + secondIDX = FindIndex( + second, + values // + ); + if (IsValidIndex(secondIDX)) + { + secondTime = swings[secondIDX].time; + } + } + } + + // + // Validate Points ... + result = + // + IsValidIndex(firstIDX) && + IsValidIndex(secondIDX) && + // + IsSpecifiedValid(firstTime) && + IsSpecifiedValid(secondTime) && + // + (isSwingLows + ? first < second + : first > second) + // + ; + if (!result) + { + return result; + } + + // + string name = ToString(type) + "_" + ToString(first) + "_" + ToString(second); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + result = mTrend.Create( + chart_id, + name, + window, + firstTime, + first, + secondTime, + second // + ); + if (!result) + { + return result; + } + + // + ObjName(name); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Trend Color ... + * + * @param value: Color ... + */ + void TrendColor(color value) + { + mTrend.Color(value); + } + + void TrendRayLeft(bool value) + { + mTrend.RayLeft(value); + } + + void TrendRayRight(bool value) + { + mTrend.RayRight(value); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TREND_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectTrend mTrend; +}; + +// +// Zone Ticks ... + +// +// Specify How to Draws Specified Levels ... +struct XTickZoneLevelSpecs +{ + // + double percent; // Max Allowed Percent of Tick Zone ... + + // + // Label Info ... + color labelColor; + string labelFont; + int labelFontSize; + double labelAngel; + + // + // Zone Info ... + bool zoneFill; + int zoneWidth; + color zoneColor; + ENUM_LINE_STYLE zoneStyle; + + // + // Constructor ... + XTickZoneLevelSpecs() + { + Default(); + } + + // + // Tools ... + + /** + * Initialize Drawing Specs ... + * + * @param _percent: Double, Max Allowed Percent ... + * @param _labelColor: Color, Specified Label Color ... + * @param _zoneColoe: Color, Specified Zone Color ... + * @param _zoneFill: Boolean, Specified Fill Zone or not ... + * @param _zoneStyle: ENUM_LINE_STYLE member, Specified Zone Style ... + * @param _labelFontSize: Integer, Specified Label Font Size ... + * @param _labelFont: String, Specified Label Font Name ... + * @param _labelAngel: Double, Specified Label Angel ... + * + * @return ( bool ) + */ + bool Init( + double _percent, + color _labelColor = clrWhite, + color _zoneColor = clrWhite, + bool _zoneFill = false, + ENUM_LINE_STYLE _zoneStyle = STYLE_DOT, + int _zoneWidth = 1, + int _labelFontSize = 12, + string _labelFont = "Arial", + double _labelAngel = 0 // + ) + { + // + bool result = false; + + // + Default(); + + // + result = _percent > 0; + if (!result) + { + return result; + } + + // + percent = _percent; + labelColor = _labelColor; + zoneColor = _zoneColor; + zoneFill = _zoneFill; + zoneStyle = _zoneStyle; + + // + if (_zoneWidth > 0) + { + zoneWidth = _zoneWidth; + } + + // + if (_labelFontSize > 0) + { + labelFontSize = _labelFontSize; + } + + // + if (IsSpecifiedValid(_labelFont)) + { + labelFont = _labelFont; + } + + // + if (_labelAngel >= 0) + { + labelAngel = _labelAngel; + } + + // + result = IsValid(); + + // + return result; + } + + /** + * Set Default Properties ... + */ + void Default() + { + // + percent = 0; + + // + // Label ... + labelAngel = 0; + labelFontSize = 13; + labelFont = "Arial"; + labelColor = clrWhite; + + // + // Zone ... + zoneWidth = 1; + zoneFill = false; + zoneColor = clrWhite; + zoneStyle = STYLE_DOT; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + percent > 0 && + // + // Zone ... + zoneWidth > 0 && + // + // Label ... + labelFontSize > 0 && + IsSpecifiedValid(labelFont) + // + ; + + // + return result; + } + + // +}; + +class XCTickZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param name: String, Specify Chart Object Identifier ... + * @param from: Datetime ... + * @param to: Datetime ... + * @param zone: XCTickZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + string name, + datetime from, + datetime to, + XCTickZone *zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + IsValid(name) && + zone.IsValid() && + IsValid(to) && + IsValid(from); + if (!result) + { + return result; + } + + // + double points = GetPoints(zone.symbol); + if (points <= 0) + { + points = 1; + } + double distance = 1 * points; + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + string rectName = "TKZ_" + name; + result = mRect.Create( + chart_id, + rectName, + window, + from, + zone.high, + to, + zone.low // + ); + if (!result) + { + return result; + } + + // + int fromToDiff = ((int)to - (int)from); + datetime labelsDate = (datetime)((int)to - (fromToDiff / 5)); + + // + string lblName = "LBLT_" + name; + result = mTLabel.Create( + chart_id, + lblName, + window, + labelsDate, + zone.high - distance // + ); + if (!result) + { + return result; + } + + // + mTLabel.Description("T: " + ToString(zone.percent) + "%"); + + // + string lblVName = "LBLV_" + name; + result = mVLabel.Create( + chart_id, + lblVName, + window, + labelsDate, + zone.low + (2.5 * distance) // + ); + if (!result) + { + return result; + } + + // + mVLabel.Description("V: " + ToString(zone.volumePercent) + "%"); + + // + ObjName(name); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TICK_ZONE_OBJ; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + /** + * Set Label Color ... + * + * @param value: Color ... + */ + void LabelColor(color value) + { + // + mTLabel.Color(value); + mVLabel.Color(value); + } + + /** + * Set Label Size ... + * + * @param value: Integer ... + */ + void LabelSize(int value) + { + // + mTLabel.FontSize(value); + mVLabel.FontSize(value); + } + + /** + * Set Label Font ... + * + * @param value: String ... + */ + void LabelFont(string value) + { + // + mTLabel.Font(value); + mVLabel.Font(value); + } + + /** + * Set Label Angle ... + * + * @param value: double ... + */ + void LabelAngle(double value) + { + // + mTLabel.Angle(value); + mVLabel.Angle(value); + } + + // + private: + // + // Props ... + CChartObjectRectangle mRect; + CChartObjectLabel mTLabel; + CChartObjectLabel mVLabel; + + // +}; +class XCTicksZoneObject : public XCBaseObject +{ + // + public: + // + + // + void ~XCTicksZoneObject() + { + mZones.Clear(); + } + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCTicksZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCTicksZone &zone, + XTickZoneLevelSpecs &specs[], + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + int levels = zone.Levels(); + result = levels > 0; + if (!result) + { + return result; + } + + // + for (int i = 0; i < levels; i++) + { + // + XCTickZone *iZone = zone.GetZone(i); + XCTickZoneObject *iObj; + iObj = new XCTickZoneObject(); + bool isCreated = iObj.Create( + chart_id, + window, + ToString(i) + "_" + name, + zone.From(), + zone.To(), + iZone, + prefix // + ); + if (!isCreated) + { + break; + } + + // + XTickZoneLevelSpecs iSpec; + bool hasSpecs = FindSpecs( + iZone, + iSpec, + specs // + ); + if (hasSpecs) + { + // + // Label ... + iObj.LabelFont(iSpec.labelFont); + iObj.LabelAngle(iSpec.labelAngel); + iObj.LabelColor(iSpec.labelColor); + iObj.LabelSize(iSpec.labelFontSize); + + // + // Zone ... + iObj.ZoneFill(iSpec.zoneFill); + iObj.ZoneColor(iSpec.zoneColor); + iObj.ZoneWidth(iSpec.zoneWidth); + iObj.ZoneStyle(iSpec.zoneStyle); + } + + // + mZones.Add(iObj); + } + + // + if (result) + { + ObjName(name); + } + else + { + mZones.Clear(); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TICKS_ZONE_OBJ; + } + + // + // Getter(s) / Setter(s) ... + + // + // Actions ... + + /** + * Destroy Object ... + */ + void Destroy() + { + mZones.Clear(); + } + + /** + * Find Specified TickZone Drawing Specs ... + * + * @param zone: XCTickZone instance, reference to Search For it ... + * @param spec: XTickZoneLevelSpecs instance, reference to Result ... + * @param specs: XTickZoneLevelSpecs instance Collection for Search ... + * + * @return ( bool ) + */ + bool FindSpecs( + XCTickZone *zone, + XTickZoneLevelSpecs &spec, + XTickZoneLevelSpecs &specs[] // + ) + { + // + bool result = false; + + // + int count = ArraySize(specs); + result = + zone.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XTickZoneLevelSpecs iSpecs = specs[i]; + + // + bool isSpecValidForZone = + !spec.IsValid() + ? zone.percent <= iSpecs.percent + : zone.percent <= iSpecs.percent && + spec.percent > iSpecs.percent; + if (isSpecValidForZone) + { + spec = iSpecs; + } + } + + // + result = spec.IsValid(); + + // + return result; + } + + // + private: + // + // Props ... + CArrayObj mZones; + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-expert.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-expert.class.mq5 new file mode 100644 index 0000000..db922b4 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-expert.class.mq5 @@ -0,0 +1,967 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCBaseExpert +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" + +// +// Definitions ... +string XCBaseExpertToken = "XCBaseEA"; + +// +// Inputs ... + +// +// Implementations ... +class XCBaseExpert : public XCBaseAlert +{ + // + public: + // + + // + XCTrade *mTrader; // Trader of Expert Adviser ... + + // + // Constructur(s) ... + void XCBaseExpert() + { + } + + // + // Deconstructor ... + void ~XCBaseExpert() + { + // + delete mTrader; + + // + ZeroMemory(mTrader); + } + + // + // Getter(s) / Setter(s) ... + + // + // Common ... + + /** + * Get Magic Number ... + * + * @return ( long ) + */ + long MagicNumber() + { + return mMagicNumber; + } + + /** + * Set Magic Number ... + * + * @param value: Long ... + */ + void MagicNumber(long value) + { + // + mMagicNumber = value; + ReConfigure(); + } + + /** + * Get Slippage ... + * + * @return ( int ) + */ + int Slippage() + { + return mSlippage; + } + + /** + * Set Slippage ... + * + * @param value: Integer ... + */ + void Slippage(int value) + { + // + mSlippage = value; + ReConfigure(); + } + + /** + * Get Tag Prefix ... + * + * @return ( string ) + */ + string TagPrefix() + { + return mTagPrefix; + } + + /** + * Set Tag Prefix ... + * + * @param value: String ... + */ + void TagPrefix(string value) + { + // + mTagPrefix = value; + ReConfigure(); + } + + // + // Symbol ... + + /** + * Get Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Set Period ... + * + * @param value: ENUM_TIMEFRAMES member ... + */ + void SetPeriod(ENUM_TIMEFRAMES value) + { + // + mPeriod = value; + ReConfigure(); + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Set Symbol ... + * + * @param value: String ... + */ + void SetSymbol(string value) + { + // + mSymbol = value; + ReConfigure(); + } + + /** + * Get Multi Symbol is Enable or Not ... + * + * @return ( bool ) + */ + bool MultiSymbol() + { + return mMultiSymbol; + } + + /** + * Set Multi Symbol is Enable or Not ... + * + * @param value: Boolean ... + */ + void MultiSymbol(bool value) + { + // + mMultiSymbol = value; + ReConfigure(); + } + + /** + * Get Multi Provided Symbols ... + * + * @return ( string ) + */ + string Symbols() + { + return mSymbols; + } + + /** + * Set Multi Provided Symbols ... + * + * @param value: String ... + */ + void Symbols(string value) + { + // + mSymbols = value; + ReConfigure(); + } + + // + // Signalling ... + + /** + * Get Force Disable Signalling ... + * + * @return ( bool ) + */ + bool Disabled() + { + return mDisabled; + } + + /** + * Set Force Disable Signalling ... + * + * @param value: Boolean ... + */ + void Disabled(bool value) + { + // + mDisabled = value; + ReConfigure(); + } + + /** + * Get Allow Long Signals ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + // + mAllowLong = value; + ReConfigure(); + } + + /** + * Get Allow Short Signalling ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signalling ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + // + mAllowShort = value; + ReConfigure(); + } + + // + // Reports ... + + /** + * Get Report New Month State ... + * + * @return ( bool ) + */ + bool ReportNewMonths() + { + return mReportNewMonths; + } + + /** + * Set Report New Month State ... + * + * @param value: Boolean ... + */ + void ReportNewMonths(bool value) + { + // + mReportNewMonths = value; + ReConfigure(); + } + + /** + * Get Report New Weeks State ... + * + * @return ( bool ) + */ + bool ReportNewWeeks() + { + return mReportNewWeeks; + } + + /** + * Set Report New Weeks State ... + * + * @param value: Boolean ... + */ + void ReportNewWeeks(bool value) + { + // + mReportNewWeeks = value; + ReConfigure(); + } + + /** + * Get Report New Days State ... + * + * @return ( bool ) + */ + bool ReportNewDays() + { + return mReportNewDays; + } + + /** + * Set Report New Days State ... + * + * @param value: Boolean ... + */ + void ReportNewDays(bool value) + { + // + mReportNewDays = value; + ReConfigure(); + } + + /** + * Get Report New Hours State ... + * + * @return ( bool ) + */ + bool ReportNewHours() + { + return mReportNewHours; + } + + /** + * Set Report New Hours State ... + * + * @param value: Boolean ... + */ + void ReportNewHours(bool value) + { + // + mReportNewHours = value; + ReConfigure(); + } + + // + // Actions ... + + /** + * Handle Expert OnInit Event ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + string message = ""; + + // + // Validate Input ... + result = ValidateInputs(); + if (!result) + { + // + message = "Invalid Inputs ...."; + + // + Alert(message); + } + + // + // Initial All Requirements ... + result = InitEA(); + if (!result) + { + return result; + } + + // + // Initial All GUI Requirements ... + result = InitGUI(); + if (!result) + { + return result; + } + + // + message = "Initialized Successfully ..."; + Alert(message); + + // + return result; + } + + /** + * Handle Expert OnDeInit Event ... + */ + void HandleOnDeInit() + { + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); + } + + /** + * Handle Expert OnTick Event ... + */ + void HandleOnTick() + { + // + UpdateGUI(); + HandleReportTime(); + HandleStrategiesOnTick(); + HandleStrategiesGuard(); + } + + /** + * Handle Expert OnTrade Event ... + */ + void HandleOnTrade() + { + mTrader.HandleOnTrade(); + } + + /** + * Handle Expert OnTimer Event ... + */ + void HandleOnTimer() + { + } + + /** + * Handle Expert OnChart Event ... + */ + void HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Virtual Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void DefaultConfigure() + { + // + // Commons ... + Slippage(10); + TagPrefix(""); + MagicNumber(1694056); + + // + // Symbol ... + SetSymbol(_Symbol); + SetPeriod(_Period); + MultiSymbol(false); + Symbols("EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb"); + + // + // Signalling ... + Disabled(false); + AllowLong(true); + AllowShort(true); + + // + string tag = GetTag(); + + // + // Alert ... + SetAlertPrefix(tag); + SetAlertLogAlerts(true); + SetAlertPushAlerts(true); + SetAlertMailAlerts(false); + SetAlertEnableAlerts(true); + SetAlertTerminalAlerts(false); + + // + // Reports ... + ReportNewDays(true); + ReportNewWeeks(false); + ReportNewHours(false); + ReportNewMonths(false); + } + + /** + * Vaslidate Inputs ... + * + * @return ( virtual bool ) + */ + virtual bool ValidateInputs() + { + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + mSlippage > 0 && + mMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + errMessage = " Errors: \n" + errMessage; + Alert(errMessage); + } + + // + return result; + } + + // + // Initializers and DeInitializers ... + + /** + * Initial EA Requirements ... + * + * @return ( virtual bool ) + */ + virtual bool InitEA() + { + // + bool result = false; + + // + // Initialize Indicator Helpers ... + + // + // Create Trader Instance and Configure it ... + mTrader = new XCTrade( + mSlippage, + mMagicNumber // + ); + + // + return result; + } + + /** + * Destroy Initialized Requirements ... + */ + virtual void DestroyEA() + { + // + delete mTrader; + + // + ZeroMemory(mTrader); + } + + /** + * GUI Initialize if required ... + * + * @return ( virtual bool ) + */ + virtual bool InitGUI() + { + // + bool result = false; + + // + result = true; + + // + return result; + } + + /** + * Update All GUI Contents ... + */ + virtual void UpdateGUI() + { + } + + /** + * Destroy all Initialized GUi Elements ... + */ + virtual void DestroyGUI() + { + } + + // + // Event Handlers ... + + /** + * Calls When a Position's SL Triggered ... + * + * @param deal: XDeal instance ... + */ + virtual void HandleOnStopLossTriggered(const XDeal &deal) + { + HandleReportBalance(); + } + + /** + * Calls When a Position's TP Triggered ... + * + * @param deal: XDeal instance ... + */ + virtual void HandleOnTakeProfitTriggered(const XDeal &deal) + { + HandleReportBalance(); + } + + /** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ + virtual void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + HandleReportBalance(); + } + + /** + * Handle Position Modified ... + * + * @param ticket: ULONG ... + * @param profit: Double ... + * @param comment: String ... + */ + virtual void HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Position Partially Closed ... + * + * @param ticket: ULONG ... + * @param profit: Double ... + * @param comment: String ... + */ + virtual void HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Deals Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnPositionsChanged(int count) + { + } + + /** + * Do All Signalling Processing Here ... + */ + virtual void HandleStrategiesOnTick() + { + } + + /** + * Check Strategies for Guards and then Apply Them ... + */ + virtual void HandleStrategiesGuard() + { + } + + // + // Time Handlers ... + + virtual void HandleOnNewMonth() + { + } + + virtual void HandleOnNewWeek() + { + } + + virtual void HandleOnNewDay() + { + } + + virtual void HandleOnNewHour() + { + } + + virtual void ReConfigure() + { + } + + /** + * Generate Identifier Tag ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + // + string result = NULL; + + // + string tagPrefix = TagPrefix(); + if (IsValid(tagPrefix)) + { + result = tagPrefix; + } + else + { + result = ""; + } + + // + result = + XCBaseExpertToken + result; + + // + return result; + } + + // + protected: + // + + // + // Props ... + + // + XTimeTracker mTimeTracker; // Time Tracker for Providing Reports ... + + // + // Actions ... + + /** + * Report Account Balance ... + */ + void HandleReportBalance() + { + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(mTrader.mAccount.GetBalance()); + Log(msg); + } + + /** + * Time Reporting based on Inputs ... + */ + void HandleReportTime() + { + // + // Monthly Report .... + if (mTimeTracker.IsNewMonth()) + { + // + HandleOnNewMonth(); + + // + if (mReportNewMonths) + { + // + string msg = "New Month ..."; + + // + Alert(msg); + } + } + + // + // Weekly Report .... + if (mTimeTracker.IsNewWeek()) + { + // + HandleOnNewWeek(); + + // + if (mReportNewWeeks) + { + // + string msg = "New Week ..."; + + // + Alert(msg); + } + } + + // + // Daily Report .... + if (mTimeTracker.IsNewDay()) + { + // + HandleOnNewDay(); + + // + if (mReportNewDays) + { + // + string msg = "New Day ..."; + + // + Alert(msg); + } + } + + // + // Hourly Report .... + if (mTimeTracker.IsNewHour()) + { + // + HandleOnNewHour(); + + // + if (mReportNewHours) + { + // + string msg = "New Hour ..."; + + // + Alert(msg); + } + } + } + + // + private: + // + + // + // Props ... + + // + // Common ... + long mMagicNumber; // Magic Number ... + int mSlippage; // Slippage ... + string mTagPrefix; // Tag Prefix ... + + // + // Symbol ... + ENUM_TIMEFRAMES mPeriod; // Period ... + string mSymbol; // Symbol ... + bool mMultiSymbol; // Multi Symbol is Enable or Not ... + string mSymbols; // Multi Provided Symbols ... + + // + // Signalling ... + bool mDisabled; // Force Disable Signalling ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + + // + // Reports ... + bool mReportNewMonths; // Report New Month ... + bool mReportNewWeeks; // Report New Weeks ... + bool mReportNewDays; // Report New Days ... + bool mReportNewHours; // Report New Hours ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-helper.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-helper.class.mq5 new file mode 100644 index 0000000..945ba69 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-helper.class.mq5 @@ -0,0 +1,151 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseHelper +// Description: provides all Base Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Definitions ... + +// +// a Class for Handle base requirements ... +// for indicators ... +class XCBaseHelper : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCBaseHelper( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame + ) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + // Deconstructor ... + void ~XCBaseHelper() + { + // + IndicatorRelease(mHandler); + } + + // + // Setter(s) / Getter(s) ... + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Retrieve Bars ... + int CountBars() + { + // + int result = + Bars( + mSymbol, + mPeriod + // + ); + + // + return result; + } + + // + // Retrieve Indicator Calculated Bars ... + int CountCalculatedBars() + { + return BarsCalculated(mHandler); + } + + // + virtual void Free() {} + + // + // Generate Tag ... + virtual string GetTag() + { + // + string result = NULL; + + // + result = + // + GetToken() + + "[" + + GetSymbol() + "|" + + ToString(GetPeriod()) + + "]" + // + ; + + // + return result; + } + + // + // Functions ... + + // + // Protected ... + protected: + // + // Props ... + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // Indicator Handler ... + int mHandler; + + // + // Private ... + private: + // +}; + +// +// Tools .... \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-http.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-http.class.mq5 new file mode 100644 index 0000000..631532f --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-http.class.mq5 @@ -0,0 +1,373 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCHttp +// Description: provides all HTTP requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Definitions ... + +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; + +// +// Imports ... + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// a Class for Manage Account ... +class XCHttp : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCHttp() + { + XCHttp("", 10000); + } + void XCHttp( + string path, // Base Folder to Store Data + int timeout // base timeout for Requests + ) + { + // + Path(path); + Timeout(timeout); + } + + // + // Deconstructor ... + void ~XCHttp() + { + } + + // + // Properties Getter(s) / Setter(s) ... + + // + // Path ... + void Path(string value) + { + // + mPath = value; + + // + if (!IsValid(mPath)) + { + mPath = GetTag(); + } + } + + string Path() + { + return mPath; + } + + // + // Timeout ... + void Timeout(int value) + { + mTimeout = value; + } + + // + int Timeout() + { + return mTimeout; + } + + // + // Error ... + int Error() + { + return mError; + } + + // + // Response ... + string Response() + { + return mResponse; + } + + // + // Overrides ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // + // Tools ... + + // + // Send Global Request ... + int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) + { + return result; + } + + // + // Reset State ... + ResetState(); + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders); + + // + if (result < 0) + { + mError = GetLastError(); + } + else + { + mResponse = CharArrayToString(response); + } + + // + return result; + } + + // + // Get Request ... + int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Post Request ... + int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Handle Download Specific URL Content to Specific Path and File Name ... + bool Download( + string url, // the URL address which going to download + string fileName // Specify Destination file name to Store Response + ) + { + // + bool result = false; + + // + string filePath = GetFilePath(fileName); + string cookie = NULL; + string referer = NULL; + int timeout = Timeout(); + + // + char payload[]; + string headers; + char response[]; + string responseHeaders; + + // + // Send Request ... + int requestResult = GetRequest( + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + // Define File Handler ... + int mFileHandler = FileOpen( + filePath, + FILE_WRITE | FILE_BIN); + if (mFileHandler == INVALID_HANDLE) + { + // + mError = GetLastError(); + return result; + } + + // + // Write Response to File ... + uint writed = FileWriteArray( + mFileHandler, + response, + 0, + ArraySize(response)); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + result = writed > 0; + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Destintion Folder Path ... + string mPath; + + // + // WEB Request Timeout Value ... + int mTimeout; + + // + // WEB Request's Response ... + string mResponse; + + // + // Error Value ... + int mError; + + // + // Private ... + private: + // + // Reset Errors State ... + void ResetState() + { + // + // Reset Errors ... + mError = -1; + mResponse = ""; + ResetLastError(); + } + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } +}; + +// +// Tools ... + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-md5.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-md5.class.mq5 new file mode 100644 index 0000000..e5cc201 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-md5.class.mq5 @@ -0,0 +1,445 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCMD5 +// Description: Provides MD5 Hashing Requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +static uchar _md5_PADDING[64] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// +#define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) +#define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// +#define _md5_FF(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_GG(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_HH(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_II(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_INIT_STATE_0 0x67452301 +#define _md5_INIT_STATE_1 0xefcdab89 +#define _md5_INIT_STATE_2 0x98badcfe +#define _md5_INIT_STATE_3 0x10325476 + +// +#define _md5_S11 7 +#define _md5_S12 12 +#define _md5_S13 17 +#define _md5_S14 22 + +// +#define _md5_S21 5 +#define _md5_S22 9 +#define _md5_S23 14 +#define _md5_S24 20 + +// +#define _md5_S31 4 +#define _md5_S32 11 +#define _md5_S33 16 +#define _md5_S34 23 + +// +#define _md5_S41 6 +#define _md5_S42 10 +#define _md5_S43 15 +#define _md5_S44 21 + +// +// END Definitions ... +// + +// +// XCMD5 a library for Hashing ... +class XCMD5 +{ + // + // Public Provides ... + public: + // + // Protected Provides ... + + // + // Constructor ... + XCMD5(void) + { + } + + // + // Deconstructor ... + ~XCMD5(void) + { + } + + // + // Hash Specified Char Array ... + string Hash( + uchar &mSource[], // Specify Char Array to Hash + int mLength = 0 // Specify Length of Char Array which required to hash + ) + { + // + string result = ""; + + // + int sourceCount = ArraySize(mSource); + + // + // Validate Args ... + if ( + sourceCount <= 0 || + (sourceCount > 0 && mLength > sourceCount)) + { + return result; + } + + // + // Normalize Args ... + if (mLength == 0) + { + mLength = sourceCount; + } + + // + // Init MD5 ... + MD5Init(); + + // + // Update Buffer ... + MD5Update(mSource, mLength); + + // + // Calculate Result ... + result = MD5Final(); + + // + return result; + } + + // + // Hash Specified String ... + string Hash( + string mSource // Specified String + ) + { + // + string result = ""; + + // + // Converts String to Char Array ... + uchar bytes[]; + StringToCharArray( + mSource, + bytes, + 0, + StringLen(mSource)); + + // + result = Hash( + bytes, + ArraySize(bytes)); + + // + return result; + } + + protected: + // + // Private Provides ... + private: + // + uint m_lMD5[4]; + uint m_nCount[2]; + uchar m_lpszBuffer[64]; + + // + // Convert Byte to DWord ... + void ByteToDWord(int &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; + } + } + + // + // Convert DWord to Byte ... + void DWordToByte(uchar &out[], int &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + // + out[j] = (uchar)(in[i] & 0xff); + out[j + 1] = (uchar)((in[i] >> 8) & 0xff); + out[j + 2] = (uchar)((in[i] >> 16) & 0xff); + out[j + 3] = (uchar)((in[i] >> 24) & 0xff); + } + } + + // + // Init MD5 Array ... + void MD5Init() + { + // + ArrayInitialize(m_lpszBuffer, 64); + + // + m_nCount[0] = m_nCount[1] = 0; + m_lMD5[0] = _md5_INIT_STATE_0; + m_lMD5[1] = _md5_INIT_STATE_1; + m_lMD5[2] = _md5_INIT_STATE_2; + m_lMD5[3] = _md5_INIT_STATE_3; + } + + // + // Update MD5 ... + void MD5Update(uchar &inBuf[], uint inLen) + { + // + int i, ii; + int mdi; + + // + uint in[16]; + int i0 = 0; + + // + mdi = (int)((m_nCount[0] >> 3) & 0x3F); + + // + if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) + { + m_nCount[1]++; + } + + // + m_nCount[0] += ((uint)inLen << 3); + m_nCount[1] += ((uint)inLen >> 29); + + // + while ((inLen--) > 0) + { + // + m_lpszBuffer[mdi++] = inBuf[i0++]; + if (mdi == 0x40) + { + // + for (i = 0, ii = 0; i < 16; i++, ii += 4) + { + in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); + } + + // + Transform(m_lMD5, in); + + // + mdi = 0; + } + } + } + + // + // Finalize an MD5 Expression ... + string MD5Final() + { + // + uchar bits[8]; + int nIndex; + uint nPadLen; + const int nMD5Size = 16; + uchar lpszMD5[16]; + string temp; + string out = ""; + int i; + + // + DWordToByte(bits, m_nCount, 8); + nIndex = (int)((m_nCount[0] >> 3) & 0x3f); + nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + MD5Update(_md5_PADDING, nPadLen); + MD5Update(bits, 8); + DWordToByte(lpszMD5, m_lMD5, nMD5Size); + + // + for (i = 0; i < nMD5Size; i++) + { + // + if (lpszMD5[i] == 0) + { + temp = "00"; + } + else if (lpszMD5[i] <= 15) + { + temp = StringFormat("0%x", lpszMD5[i]); + } + else + { + temp = StringFormat("%x", lpszMD5[i]); + } + + // + out += temp; + } + + // + lpszMD5[0] = '\0'; + + // + return (out); + } + + // + // Transform Buffers ... + void Transform(uint &buf[], uint &in[]) + { + // + uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // + _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); + _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); + _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); + _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); + _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); + _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); + _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); + _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); + _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); + _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); + _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); + _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); + _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); + _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); + _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); + _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); + + // + _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); + _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); + _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); + _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); + _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); + _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); + _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); + _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); + _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); + _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); + _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); + _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); + _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); + _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); + _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); + _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); + + // + _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); + _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); + _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); + _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); + _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); + _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); + _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); + _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); + _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); + _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); + _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); + _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); + _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); + _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); + _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); + _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); + + // + _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); + _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); + _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); + _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); + _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); + _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); + _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); + _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); + _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); + _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); + _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); + _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); + _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); + _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); + _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); + _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); + + // + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + } +}; diff --git a/BKPS/14031218/Classes/x-saherelm.x-poi.class.ex5 b/BKPS/14031218/Classes/x-saherelm.x-poi.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..8aef304f6f37c1f222f4a137f6adea1147cca434 GIT binary patch literal 8328 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 + +// +// Implementation ... + +// +// POI Detector Class ... +class XCPOIDetector : public XCBaseAlert +{ + // + public: + // + + // + // Constructors ... + /** + * Create an Instance ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + */ + void XCPOIDetector( + string symbol, + ENUM_TIMEFRAMES period) + { + // + // Attach Required Properties ... + mSymbol = symbol; + mPeriod = period; + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + mSymbol, + mPeriod // + ); + + // + mBarAnalyser = new XCBarAnalyser(); + + // + // Apply Default Configurations ... + Default(); + } + + // + // Deconstructor ... + void ~XCPOIDetector() + { + Destroy(); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Retrieve Detector Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve Detector Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Get Max Required POI(s) allowed to Holds ... + * + * @return ( int ) + */ + int MaxRequiredPOIs() + { + return mMaxRequiredPOIs; + } + + /** + * Set Max Required POI(s) allowed to Holds ... + * + * @param value: int ... + */ + void MaxRequiredPOIs(int value) + { + // + if (value < 0) + { + value = 5; + } + + // + mMaxRequiredPOIs = value; + } + + /** + * Get Max Allowed Loopback for POI(s) Detection on Initialization Process ... + * + * @return ( int ) + */ + int MaxAllowedLoopbackForInit() + { + return maxAllowedLoopbackForInit; + } + + /** + * Set Max Allowed Loopback for POI(s) Detection on Initialization Process ... + * + * @param value: int ... + */ + void MaxAllowedLoopbackForInit(int value) + { + // + if (value < 0) + { + value = 578; + } + + // + maxAllowedLoopbackForInit = value; + } + + /** + * Get Swing Range Validation ... + * + * @return ( int ) + */ + int SwingRange() + { + return mSwingRange; + } + + /** + * Set Swing Range Validation ... + * + * @param value: int ... + */ + void SwingRange(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingRange = value; + } + + /** + * Get Momentum Bar Detection Extends Range ... + * + * @return ( int ) + */ + int MomentumExtend() + { + return mMomentumExtend; + } + + /** + * Set Momentum Bar Detection Extends Range ... + * + * @param value: int ... + */ + void MomentumExtend(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumExtend = value; + } + + /** + * Get Momentum Bar Detection Body Percent ... + * + * @return ( double ) + */ + double MomentumBodyPercent() + { + return mMomentumBodyPercent; + } + + /** + * Set Momentum Bar Detection Body Percent ... + * + * @param value: double ... + */ + void MomentumBodyPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + if (value > 100) + { + value = 100; + } + + // + mMomentumBodyPercent = value; + } + + /** + * Get Rejection Bar Detection Extends Range ... + * + * @return ( int ) + */ + int RejectionExtend() + { + return mRejectionExtend; + } + + /** + * Set Rejection Bar Detection Extends Range ... + * + * @param value: int ... + */ + void RejectionExtend(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRejectionExtend = value; + } + + /** + * Get Rejection Bar Detection Shadow Percent ... + * + * @return ( double ) + */ + double RejectionShadowPercent() + { + return mRejectionShadowPercent; + } + + /** + * Set Rejection Bar Detection Shadow Percent ... + * + * @param value: double ... + */ + void RejectionShadowPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + if (value > 100) + { + value = 100; + } + + // + mRejectionShadowPercent = value; + } + + /** + * Get Support and Resistance Detection Range ... + * + * @return ( int ) + */ + int SupResRange() + { + return mSupResRange; + } + + /** + * Set Support and Resistance Detection Range ... + * + * @param value: int ... + */ + void SupResRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSupResRange = value; + } + + /** + * Get use Support and Resistance Range as Start ... + * + * @return ( bool ) + */ + bool SupResRangeAsStart() + { + return mSupResRangeAsStart; + } + + /** + * Set use Support and Resistance Range as Start ... + * @param value: bool ... + */ + void SupResRangeAsStart(bool value) + { + mSupResRangeAsStart = value; + } + + /** + * Get OrderBlock Detection Same Bars ... + * + * @return ( int ) + */ + int OrderBlockSameBars() + { + return mOrderBlockSameBars; + } + + /** + * Set OrderBlock Detection Same Bars ... + * + * @param value: int ... + */ + void OrderBlockSameBars(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mOrderBlockSameBars = value; + } + + /** + * Get FairValueGap Detection Same Bars ... + * + * @return ( int ) + */ + int FairValueGapSameBars() + { + return mFairValueGapSameBars; + } + + /** + * Set FairValueGap Detection Same Bars ... + * + * @param value: int ... + */ + void FairValueGapSameBars(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mFairValueGapSameBars = value; + } + + /** + * Get Minimum Length of Cnsolidation Zone ... + * + * @return ( int ) + */ + int ConsolidationZoneMinLoopback() + { + return mConsolidationZoneMinLoopback; + } + + /** + * Set Minimum Length of Cnsolidation Zone ... + * + * @param value: int ... + */ + void ConsolidationZoneMinLoopback(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mConsolidationZoneMinLoopback = value; + } + + /** + * Get Consolidation Zone Range in Point ... + * + * @return ( double ) + */ + double ConsolidationZoneRangeInPoint() + { + return mConsolidationZoneRangeInPoint; + } + + /** + * Set Consolidation Zone Range in Point ... + * + * @param value: double + */ + void ConsolidationZoneRangeInPoint(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + mConsolidationZoneRangeInPoint = value; + } + + /** + * Get Consolidation Zone Upper Applied To ... + * + * @return ( ENUM_APPLIED_PRICE ) + */ + ENUM_APPLIED_PRICE ConsolidationZonesLowerAppliedTo() + { + return mConsolidationZonesLowerAppliedTo; + } + + /** + * Set Consolidation Zone Upper Applied To ... + * + * @param value: ENUM_APPLIED_PRICE + */ + void ConsolidationZonesLowerAppliedTo(ENUM_APPLIED_PRICE value = PRICE_LOW) + { + mConsolidationZonesLowerAppliedTo = value; + } + + /** + * Get Consolidation Zone Lower Applied To ... + * + * @return ( ENUM_APPLIED_PRICE ) + */ + ENUM_APPLIED_PRICE ConsolidationZonesUpperAppliedTo() + { + return mConsolidationZonesUpperAppliedTo; + } + + /** + * Set Consolidation Zone Lower Applied To ... + * + * @param value: ENUM_APPLIED_PRICE + */ + void ConsolidationZonesUpperAppliedTo(ENUM_APPLIED_PRICE value = PRICE_HIGH) + { + mConsolidationZonesUpperAppliedTo = value; + } + + // + // Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Default Props ... + SwingRange(3); + SupResRange(21); + MomentumExtend(1); + RejectionExtend(1); + MaxRequiredPOIs(100); + OrderBlockSameBars(3); + FairValueGapSameBars(3); + MomentumBodyPercent(70); + SupResRangeAsStart(true); + RejectionShadowPercent(70); + MaxAllowedLoopbackForInit(578); + ConsolidationZoneMinLoopback(5); + ConsolidationZoneRangeInPoint(50); + ConsolidationZonesLowerAppliedTo(PRICE_LOW); + ConsolidationZonesUpperAppliedTo(PRICE_HIGH); + } + + /** + * Add Event Listener ... + * + * @param listener: TOnPOIEvent instance ... + */ + void AddEventListener(TOnPOIEvent listener) + { + // + Add( + listener, + mEventListeners // + ); + } + + /** + * Initialize Instance ... + */ + void Init( + int barIndex = 0, + bool ignoreMaxAllowed = true // + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (maxAllowedLoopbackForInit <= 0) + { + return; + } + + // + mLock = true; + bool canContinue = true; + int index = barIndex + maxAllowedLoopbackForInit; + if (!IsValidIndex(index)) + { + // + mLock = false; + return; + } + + // + while (canContinue) + { + // + XOHCL iBar; + bool has = iBar.Init( + mSymbol, + mPeriod, + index // + ); + index--; + + // + int count = 0; + ENUM_XPOI_EVENTS iEvent = X_POI_EVENT_NONE; + + // + // Swings ... + DetectSwing( + iBar, + iEvent, + false // + ); + + // + // Rejection Bar ... + DetectRejectionBar( + iBar, + iEvent, + false // + ); + // + // Momentum Bar ... + DetectMomentumBar( + iBar, + iEvent, + false // + ); + + // + // Support ... + DetectSupportZone( + iBar, + iEvent, + false // + ); + + // + // Demand ... + DetectDemandZone( + iBar, + iEvent, + false // + ); + + // + // Resistance ... + DetectResistanceZone( + iBar, + iEvent, + false // + ); + + // + // Supply ... + DetectSupplyZone( + iBar, + iEvent, + false // + ); + + // + // OrderBlock ... + DetectOrderBlock( + iBar, + iEvent, + false // + ); + + // + // FairValueGap ... + DetectFairValueGap( + iBar, + iEvent, + false // + ); + + // + // Consolidation Zone ... + DetectConsolidationZone( + iBar, + iEvent, + false // + ); + + // + canContinue = + has && + index >= 0; + + // + iBar.Clean(); + } + + // + ReverseCollections(); + + // + mLock = false; + } + + /** + * Update POI(s) ... + * @param events: ENUM_XPOI_EVENTS member Collection ... + */ + void Update( + ENUM_XPOI_EVENTS &events[], + int barIndex = 0 // + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Clean(events); + + // + if (mLock) + { + return; + } + + // + // Check Bar Tracker if Waits ... + if (!mBarTracker.IsNewBar()) + { + return; + } + + // + mLock = true; + + // + XOHCL iBar; + bool has = iBar.Init( + mSymbol, + mPeriod, + barIndex // + ); + + // + if (!has) + { + // + iBar.Clean(); + + // + return; + } + + // + int count = 0; + ENUM_XPOI_EVENTS iEvent = X_POI_EVENT_NONE; + + // + // Swings ... + has = DetectSwing( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCSwing *iSwing = NULL; + if (iEvent == X_SWING_LOW_DETECTED) + { + // + has = GetLastItem( + iSwing, + mSwingLows // + ); + } + else if (iEvent == X_SWING_HIGH_DETECTED) + { + // + has = GetLastItem( + iSwing, + mSwingHighs // + ); + } + if (has) + { + item = (XCBasePOI *)iSwing; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Momentum Bar ... + has = DetectMomentumBar( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCMomentumBar *iMomentum = NULL; + if (iEvent == X_BULLISH_MOMENTUM_BAR_DETECTED) + { + // + has = GetLastItem( + iMomentum, + mBullishMomentumBars // + ); + } + else if (iEvent == X_BEARISH_MOMENTUM_BAR_DETECTED) + { + // + has = GetLastItem( + iMomentum, + mBearishMomentumBars // + ); + } + if (has) + { + item = (XCBasePOI *)iMomentum; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Rejection Bar ... + has = DetectRejectionBar( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCRejectionBar *iRejection = NULL; + if (iEvent == X_BULLISH_REJECTION_BAR_DETECTED) + { + // + has = GetLastItem( + iRejection, + mBullishRejectionBars // + ); + } + else if (iEvent == X_BEARISH_REJECTION_BAR_DETECTED) + { + // + has = GetLastItem( + iRejection, + mBearishRejectionBars // + ); + } + if (has) + { + item = (XCBasePOI *)iRejection; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Support ... + has = DetectSupportZone( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCSupportZone *iZone = NULL; + has = GetLastItem( + iZone, + mSupportZones // + ); + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Demand ... + has = DetectDemandZone( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCDemandZone *iZone = NULL; + has = GetLastItem( + iZone, + mDemandZones // + ); + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Resistance ... + has = DetectResistanceZone( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCResistanceZone *iZone = NULL; + has = GetLastItem( + iZone, + mResistanceZones // + ); + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // Supply ... + has = DetectSupplyZone( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCSupplyZone *iZone = NULL; + has = GetLastItem( + iZone, + mSupplyZones // + ); + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // OrderBlock ... + has = DetectOrderBlock( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCOrderBlock *iZone = NULL; + if (iEvent == X_BULLISH_ORDERBLOCK_DETECTED) + { + // + has = GetLastItem( + iZone, + mBullishOrderBlocks // + ); + } + else if (iEvent == X_BEARISH_ORDERBLOCK_DETECTED) + { + // + has = GetLastItem( + iZone, + mBearishOrderBlocks // + ); + } + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + // FairValueGap ... + has = DetectFairValueGap( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + + // + XCBasePOI *item = NULL; + XCFVG *iZone = NULL; + if (iEvent == X_BULLISH_FVG_DETECTED) + { + // + has = GetLastItem( + iZone, + mBullishFairValueGaps // + ); + } + else if (iEvent == X_BEARISH_FVG_DETECTED) + { + // + has = GetLastItem( + iZone, + mBearishFairValueGaps // + ); + } + if (has) + { + item = (XCBasePOI *)iZone; + } + + // + has = item != NULL; + if (has) + { + // + NotifyEventListeners( + iEvent, + item // + ); + } + } + + // + has = DetectConsolidationZone( + iBar, + iEvent // + ); + if (has) + { + // + Add( + iEvent, + events // + ); + } + + // + iBar.Clean(); + mLock = false; + // mBarTracker.Waits(); + + // + if (HasChild(events)) + { + CleanupUnusedCollections(); + } + } + + /** + * Get Current State of POIs ... + * + * @param state: XPOIState instance ... + */ + void GetState( + XPOIState &state // + ) + { + // + state.Clean(); + + // + state.symbol = mSymbol; + state.period = mPeriod; + state.time = TimeCurrent(); + + // + Copy( + mSwings, + state.swings // + ); + + // + Copy( + mSwingHighs, + state.swingHighs // + ); + + // + Copy( + mSwingLows, + state.swingLows // + ); + + // + Copy( + mMomentumBars, + state.momentumBars // + ); + + // + Copy( + mBullishMomentumBars, + state.bullishMomentumBars // + ); + + // + Copy( + mBearishMomentumBars, + state.bearishMomentumBars // + ); + + // + Copy( + mRejectionBars, + state.rejectionBars // + ); + + // + Copy( + mBullishRejectionBars, + state.bullishRejectionBars // + ); + + // + Copy( + mBearishRejectionBars, + state.bearishRejectionBars // + ); + + // + Copy( + mSupportZones, + state.supportZones // + ); + + // + Copy( + mResistanceZones, + state.resistanceZones // + ); + + // + Copy( + mSupplyZones, + state.supplyZones // + ); + + // + Copy( + mDemandZones, + state.demandZones // + ); + + // + Copy( + mOrderBlocks, + state.orderBlocks // + ); + + // + Copy( + mBullishOrderBlocks, + state.bullishOrderBlocks // + ); + + // + Copy( + mBearishOrderBlocks, + state.bearishOrderBlocks // + ); + + // + Copy( + mFairValueGaps, + state.fairValueGaps // + ); + + // + Copy( + mBullishFairValueGaps, + state.bullishFairValueGaps // + ); + + // + Copy( + mBearishFairValueGaps, + state.bearishFairValueGaps // + ); + + // + Copy( + mConsolidationZones, + state.consolidationZones // + ); + + // + Copy( + mBullishConsolidationZones, + state.bullishConsolidationZones // + ); + + // + Copy( + mBearishConsolidationZones, + state.bearishConsolidationZones // + ); + + // + } + + /** + * Destroy Instance ... + */ + void Destroy() + { + // + mBarTracker.Clean(); + ZeroMemory(mBarAnalyser); + + // + CleanCollections(); + } + + // + // + // + // + // + // + + /** + * Detect Swing Bars ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectSwing( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir; + result = mBarAnalyser.IsSwing( + bar, + iDir, + mSwingRange // + ); + + // + result = result && + HasDirection(iDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(iDir); + bool isBearish = IsBearish(iDir); + + // + ENUM_XPOIS type = + isBullish + ? X_POI_SWING_LOW + : X_POI_SWING_HIGH; + + // + // Swing Object ... + XCSwing *swing; + swing = new XCSwing(); + result = swing.Init( + bar, + type // + ); + if (!result) + { + return result; + } + + // + // Add ... + + // + int idx = FindIndex( + swing, + mSwings // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mSwings); + + // + Add( + swing, + mSwings // + ); + + // + ArrayReverse(mSwings); + } + else + { + // + Add( + swing, + mSwings // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mSwings); + + // + Add( + swing, + mSwings // + ); + + // + ArrayReverse(mSwings); + } + else + { + // + Add( + swing, + mSwingLows // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mSwingHighs); + + // + Add( + swing, + mSwingHighs // + ); + + // + ArrayReverse(mSwingHighs); + } + else + { + // + Add( + swing, + mSwingHighs // + ); + } + } + + // + state = + isBullish + ? X_SWING_LOW_DETECTED + : X_SWING_HIGH_DETECTED; + + // + return result; + } + + /** + * Detect Momentum Bars ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectMomentumBar( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir; + result = mBarAnalyser.IsMomentumBar( + bar, + iDir, + mMomentumExtend, // Extends ... + mMomentumBodyPercent // Body Percent ... + ); + + // + result = result && + HasDirection(iDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(iDir); + bool isBearish = IsBearish(iDir); + + // + ENUM_XPOIS type = + isBullish + ? X_POI_MOMENTUM_BAR + : X_POI_MOMENTUM_BAR; + + // + // Swing Object ... + XCMomentumBar *momentum; + momentum = new XCMomentumBar(); + result = momentum.Init( + bar // + ); + if (!result) + { + return result; + } + + // + int idx = FindIndex( + momentum, + mMomentumBars // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + + // + // Add ... + if (reversal) + { + // + ArrayReverse(mMomentumBars); + + // + Add( + momentum, + mMomentumBars // + ); + + // + ArrayReverse(mMomentumBars); + } + else + { + // + Add( + momentum, + mMomentumBars // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBullishMomentumBars); + + // + Add( + momentum, + mBullishMomentumBars // + ); + + // + ArrayReverse(mBullishMomentumBars); + } + else + { + // + Add( + momentum, + mBullishMomentumBars // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBearishMomentumBars); + + // + Add( + momentum, + mBearishMomentumBars // + ); + + // + ArrayReverse(mBearishMomentumBars); + } + else + { + // + Add( + momentum, + mBearishMomentumBars // + ); + } + } + + // + state = + isBullish + ? X_BULLISH_MOMENTUM_BAR_DETECTED + : X_BEARISH_MOMENTUM_BAR_DETECTED; + + // + return result; + } + + /** + * Detect Rejection Bars ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectRejectionBar( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir; + result = mBarAnalyser.IsRejectionBar( + bar, + iDir, + mRejectionExtend, // Extends ... + mRejectionShadowPercent // Shadow Percent ... + ); + + // + result = result && + HasDirection(iDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(iDir); + bool isBearish = IsBearish(iDir); + + // + ENUM_XPOIS type = + isBullish + ? X_POI_MOMENTUM_BAR + : X_POI_MOMENTUM_BAR; + + // + // Swing Object ... + XCRejectionBar *rejection; + rejection = new XCRejectionBar(); + result = rejection.Init( + bar // + ); + if (!result) + { + return result; + } + + // + int idx = FindIndex( + rejection, + mRejectionBars // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + + // + // Add ... + if (reversal) + { + // + ArrayReverse(mRejectionBars); + + // + Add( + rejection, + mRejectionBars // + ); + + // + ArrayReverse(mRejectionBars); + } + else + { + // + Add( + rejection, + mRejectionBars // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBullishRejectionBars); + + // + Add( + rejection, + mBullishRejectionBars // + ); + + // + ArrayReverse(mBullishRejectionBars); + } + else + { + // + Add( + rejection, + mBullishRejectionBars // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBearishRejectionBars); + + // + Add( + rejection, + mBearishRejectionBars // + ); + + // + ArrayReverse(mBearishRejectionBars); + } + else + { + // + Add( + rejection, + mBearishRejectionBars // + ); + } + } + + // + state = + isBullish + ? X_BULLISH_REJECTION_BAR_DETECTED + : X_BEARISH_REJECTION_BAR_DETECTED; + + // + return result; + } + + /** + * Detect Support Zone ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectSupportZone( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL supportBar; + result = mBarAnalyser + .HasSupport( + bar, + supportBar, + mSupResRange // + ); + if (!result) + { + // + supportBar.Clean(); + + // + return result; + } + + // + XCSupportZone *supportZone; + supportZone = new XCSupportZone(); + result = supportZone.Init( + supportBar, + mSupResRange, + mSupResRangeAsStart // Use Range As Start ... + ); + if (!result) + { + // + supportBar.Clean(); + ZeroMemory(supportZone); + + // + return result; + } + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = supportZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + supportBar.Clean(); + activationBar.Clean(); + ZeroMemory(supportZone); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + // Add ... + + // + int idx = FindIndex( + supportZone, + mSupportZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + supportBar.Clean(); + ZeroMemory(supportZone); + + // + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mSupportZones); + + // + Add( + supportZone, + mSupportZones // + ); + + // + ArrayReverse(mSupportZones); + } + else + { + // + Add( + supportZone, + mSupportZones // + ); + } + + // + state = X_SUPPORT_ZONE_DETECTED; + + // + supportBar.Clean(); + + // + return result; + } + + /** + * Detect Resistance Zone ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectResistanceZone( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL resistanceBar; + result = mBarAnalyser + .HasResistance( + bar, + resistanceBar, + mSupResRange // + ); + if (!result) + { + // + resistanceBar.Clean(); + + // + return result; + } + + // + XCResistanceZone *resistanceZone; + resistanceZone = new XCResistanceZone(); + result = resistanceZone.Init( + resistanceBar, + mSupResRange, + mSupResRangeAsStart // Use Range As Start ... + ); + if (!result) + { + // + resistanceBar.Clean(); + ZeroMemory(resistanceZone); + + // + return result; + } + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = resistanceZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + resistanceBar.Clean(); + activationBar.Clean(); + ZeroMemory(resistanceZone); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + // Add ... + + // + int idx = FindIndex( + resistanceZone, + mResistanceZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + resistanceBar.Clean(); + ZeroMemory(resistanceZone); + + // + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mResistanceZones); + + // + Add( + resistanceZone, + mResistanceZones // + ); + + // + ArrayReverse(mResistanceZones); + } + else + { + // + Add( + resistanceZone, + mResistanceZones // + ); + } + + // + state = X_RESISTANCE_ZONE_DETECTED; + + // + resistanceBar.Clean(); + + // + return result; + } + + /** + * Detect Supply Zone ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectSupplyZone( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int mSupDemRange = mSupResRange * 2; + + // + XOHCL supplyBar; + result = mBarAnalyser + .HasResistance( + bar, + supplyBar, + mSupDemRange // + ); + if (!result) + { + // + supplyBar.Clean(); + + // + return result; + } + + // + XCSupplyZone *supplyZone; + supplyZone = new XCSupplyZone(); + result = supplyZone.Init( + supplyBar, + mSupDemRange, + mSupResRangeAsStart // Use Range As Start ... + ); + if (!result) + { + // + supplyBar.Clean(); + ZeroMemory(supplyZone); + + // + return result; + } + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = supplyZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + supplyBar.Clean(); + activationBar.Clean(); + ZeroMemory(supplyZone); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + // Add ... + + // + int idx = FindIndex( + supplyZone, + mSupplyZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + supplyBar.Clean(); + ZeroMemory(supplyZone); + + // + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mSupplyZones); + + // + Add( + supplyZone, + mSupplyZones // + ); + + // + ArrayReverse(mSupplyZones); + } + else + { + // + Add( + supplyZone, + mSupplyZones // + ); + } + + // + state = X_SUPPLY_ZONE_DETECTED; + + // + supplyBar.Clean(); + + // + return result; + } + + /** + * Detect Demand Zone ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectDemandZone( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int mSupDemRange = mSupResRange * 2; + + // + XOHCL demandBar; + result = mBarAnalyser + .HasSupport( + bar, + demandBar, + mSupDemRange // + ); + if (!result) + { + // + demandBar.Clean(); + + // + return result; + } + + // + XCDemandZone *demandZone; + demandZone = new XCDemandZone(); + result = demandZone.Init( + demandBar, + mSupDemRange, + mSupResRangeAsStart // Use Range As Start ... + ); + if (!result) + { + // + demandBar.Clean(); + ZeroMemory(demandZone); + + // + return result; + } + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = demandZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + demandBar.Clean(); + activationBar.Clean(); + ZeroMemory(demandZone); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + // Add ... + + // + int idx = FindIndex( + demandZone, + mDemandZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + demandBar.Clean(); + ZeroMemory(demandZone); + + // + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mDemandZones); + + // + Add( + demandZone, + mDemandZones // + ); + + // + ArrayReverse(mDemandZones); + } + else + { + // + Add( + demandZone, + mDemandZones // + ); + } + + // + state = X_DEMAND_ZONE_DETECTED; + + // + demandBar.Clean(); + + // + return result; + } + + /** + * Detect Order Blocks ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectOrderBlock( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION obDir; + result = mBarAnalyser.HasOrderBlock( + bar, + obBar, + obDir, + mOrderBlockSameBars // + ); + if (!result) + { + // + obBar.Clean(); + + // + return result; + } + + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + obDir // + ); + if (!result) + { + // + obBar.Clean(); + ZeroMemory(ob); + + // + return result; + } + + // + bool isBullish = IsBullish(obDir); + bool isBearish = IsBearish(obDir); + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = ob.IsActivated( + obDir, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + obBar.Clean(); + activationBar.Clean(); + ZeroMemory(ob); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + int idx = FindIndex( + ob, + mOrderBlocks // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + obBar.Clean(); + ZeroMemory(ob); + + // + return result; + } + + // + // Add ... + if (reversal) + { + // + ArrayReverse(mOrderBlocks); + + // + Add( + ob, + mOrderBlocks // + ); + + // + ArrayReverse(mOrderBlocks); + } + else + { + // + Add( + ob, + mOrderBlocks // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBullishOrderBlocks); + + // + Add( + ob, + mBullishOrderBlocks // + ); + + // + ArrayReverse(mBullishOrderBlocks); + } + else + { + // + Add( + ob, + mBullishOrderBlocks // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBearishOrderBlocks); + + // + Add( + ob, + mBearishOrderBlocks // + ); + + // + ArrayReverse(mBearishOrderBlocks); + } + else + { + // + Add( + ob, + mBearishOrderBlocks // + ); + } + } + + // + state = + isBullish + ? X_BULLISH_ORDERBLOCK_DETECTED + : X_BEARISH_ORDERBLOCK_DETECTED; + + // + obBar.Clean(); + + // + return result; + } + + /** + * Detect Fair Value Gaps ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectFairValueGap( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false, + bool forceActivation = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL fvgStartBar; + XOHCL fvgEndBar; + ENUM_X_DIRECTION fvgDir; + result = mBarAnalyser.HasFairValueGap( + bar, + fvgStartBar, + fvgEndBar, + fvgDir, + mFairValueGapSameBars // + ); + if (!result) + { + // + fvgEndBar.Clean(); + fvgStartBar.Clean(); + + // + return result; + } + + // + XCFVG *fvg; + fvg = new XCFVG(); + result = fvg.Init( + fvgStartBar, + fvgEndBar, + fvgDir // + ); + if (!result) + { + // + ZeroMemory(fvg); + fvgEndBar.Clean(); + fvgStartBar.Clean(); + + // + return result; + } + + // + bool isBullish = IsBullish(fvgDir); + bool isBearish = IsBearish(fvgDir); + + // + // Check Zone Not Activated ... + if (forceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = fvg.IsActivated( + fvgDir, + activationBar, + isActivationBarBodyIn, + false, + bar.period // + ); + result = !isActivated; + if (!result) + { + // + ZeroMemory(fvg); + fvgEndBar.Clean(); + fvgStartBar.Clean(); + activationBar.Clean(); + + // + return result; + } + + // + activationBar.Clean(); + } + + // + int idx = FindIndex( + fvg, + mFairValueGaps // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + ZeroMemory(fvg); + fvgEndBar.Clean(); + fvgStartBar.Clean(); + + // + return result; + } + + // + // Add ... + if (reversal) + { + // + ArrayReverse(mFairValueGaps); + + // + Add( + fvg, + mFairValueGaps // + ); + + // + ArrayReverse(mFairValueGaps); + } + else + { + // + Add( + fvg, + mFairValueGaps // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBullishFairValueGaps); + + // + Add( + fvg, + mBullishFairValueGaps // + ); + + // + ArrayReverse(mBullishFairValueGaps); + } + else + { + // + Add( + fvg, + mBullishFairValueGaps // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBearishFairValueGaps); + + // + Add( + fvg, + mBearishFairValueGaps // + ); + + // + ArrayReverse(mBearishFairValueGaps); + } + else + { + // + Add( + fvg, + mBearishFairValueGaps // + ); + } + } + + // + state = + isBullish + ? X_BULLISH_FVG_DETECTED + : X_BEARISH_FVG_DETECTED; + + // + fvgEndBar.Clean(); + fvgStartBar.Clean(); + + // + return result; + } + + /** + * Detect Consolidation Zones ... + * + * @param bar: XOHCL instance ... + * @param reversal: boolean reversal add to collection ... + * + * @return ( bool ) + */ + bool DetectConsolidationZone( + XOHCL &bar, + ENUM_XPOI_EVENTS &state, + bool reversal = false // + ) + { + // + bool result = false; + + // + state = X_POI_EVENT_NONE; + + // + XConsolidationZone cZone; + result = mBarAnalyser.HasConsolidationZone( + bar, + cZone, + mConsolidationZoneMinLoopback, + mConsolidationZoneRangeInPoint, + mConsolidationZonesUpperAppliedTo, + mConsolidationZonesLowerAppliedTo // + ); + if (!result) + { + // + cZone.Clean(); + + // + return result; + } + + // + // Add ... + + // + bool isBullish = IsBullish(cZone.dir); + bool isBearish = IsBearish(cZone.dir); + + // + int idx = FindIndex( + cZone, + mConsolidationZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + cZone.Clean(); + + // + return result; + } + + // + if (reversal) + { + // + ArrayReverse(mConsolidationZones); + + // + AddRef( + cZone, + mConsolidationZones // + ); + + // + ArrayReverse(mConsolidationZones); + } + else + { + // + AddRef( + cZone, + mConsolidationZones // + ); + } + + // + if (isBullish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBullishConsolidationZones); + + // + AddRef( + cZone, + mBullishConsolidationZones // + ); + + // + ArrayReverse(mBullishConsolidationZones); + } + else + { + // + AddRef( + cZone, + mBullishConsolidationZones // + ); + } + } + else if (isBearish) + { + // + // Add Swings ... + if (reversal) + { + // + ArrayReverse(mBearishConsolidationZones); + + // + AddRef( + cZone, + mBearishConsolidationZones // + ); + + // + ArrayReverse(mBearishConsolidationZones); + } + else + { + // + AddRef( + cZone, + mBearishConsolidationZones // + ); + } + } + + // + state = + IsBullish(cZone.dir) + ? X_BULLISH_CONSOLIDATION_ZONE_DETECTED + : X_BEARISH_CONSOLIDATION_ZONE_DETECTED; + + // + cZone.Clean(); + + // + return result; + } + + // + protected: + // + + // + void CleanCollections() + { + // + Clean(mSwings); + Clean(mSwingLows); + Clean(mSwingHighs); + Clean(mDemandZones); + Clean(mSupplyZones); + Clean(mOrderBlocks); + Clean(mMomentumBars); + Clean(mSupportZones); + Clean(mRejectionBars); + Clean(mFairValueGaps); + Clean(mEventListeners); + Clean(mResistanceZones); + Clean(mBullishOrderBlocks); + Clean(mBearishOrderBlocks); + Clean(mConsolidationZones); + Clean(mBullishMomentumBars); + Clean(mBearishMomentumBars); + Clean(mBullishRejectionBars); + Clean(mBearishRejectionBars); + Clean(mBullishFairValueGaps); + Clean(mBearishFairValueGaps); + Clean(mBullishConsolidationZones); + Clean(mBearishConsolidationZones); + } + + // + void ReverseCollections() + { + // + ArrayReverse(mSwings); + ArrayReverse(mSwingLows); + ArrayReverse(mSwingHighs); + ArrayReverse(mDemandZones); + ArrayReverse(mSupplyZones); + ArrayReverse(mOrderBlocks); + ArrayReverse(mMomentumBars); + ArrayReverse(mSupportZones); + ArrayReverse(mRejectionBars); + ArrayReverse(mFairValueGaps); + ArrayReverse(mEventListeners); + ArrayReverse(mResistanceZones); + ArrayReverse(mBullishOrderBlocks); + ArrayReverse(mBearishOrderBlocks); + ArrayReverse(mConsolidationZones); + ArrayReverse(mBullishMomentumBars); + ArrayReverse(mBearishMomentumBars); + ArrayReverse(mBullishRejectionBars); + ArrayReverse(mBearishRejectionBars); + ArrayReverse(mBullishFairValueGaps); + ArrayReverse(mBearishFairValueGaps); + ArrayReverse(mBullishConsolidationZones); + ArrayReverse(mBearishConsolidationZones); + } + + // + void CleanupUnusedCollections( + int maxAllowed = 0 // + ) + { + // + maxAllowed = MaxRequiredPOIs(); + + // + if (maxAllowed <= 0) + { + return; + } + + // + CleanupArray( + mEventListeners, + maxAllowed // + ); + + // + CleanupArray( + mSwings, + maxAllowed // + ); + + // + CleanupArray( + mSwingLows, + maxAllowed // + ); + + // + CleanupArray( + mSwingHighs, + maxAllowed // + ); + + // + CleanupArray( + mMomentumBars, + maxAllowed // + ); + + // + CleanupArray( + mBullishMomentumBars, + maxAllowed // + ); + + // + CleanupArray( + mBearishMomentumBars, + maxAllowed // + ); + + // + CleanupArray( + mRejectionBars, + maxAllowed // + ); + + // + CleanupArray( + mBullishRejectionBars, + maxAllowed // + ); + + // + CleanupArray( + mBearishRejectionBars, + maxAllowed // + ); + + // + CleanupArray( + mSupportZones, + maxAllowed // + ); + + // + CleanupArray( + mDemandZones, + maxAllowed // + ); + + // + CleanupArray( + mSupplyZones, + maxAllowed // + ); + + // + CleanupArray( + mResistanceZones, + maxAllowed // + ); + + // + CleanupArray( + mFairValueGaps, + maxAllowed // + ); + + // + CleanupArray( + mBullishFairValueGaps, + maxAllowed // + ); + + // + CleanupArray( + mBearishFairValueGaps, + maxAllowed // + ); + + // + CleanupArray( + mOrderBlocks, + maxAllowed // + ); + + // + CleanupArray( + mBullishOrderBlocks, + maxAllowed // + ); + + // + CleanupArray( + mBearishOrderBlocks, + maxAllowed // + ); + + // + CleanupArray( + mConsolidationZones, + maxAllowed // + ); + + // + CleanupArray( + mBullishConsolidationZones, + maxAllowed // + ); + + // + CleanupArray( + mBearishConsolidationZones, + maxAllowed // + ); + + // + } + + /** + * Notify Event Listeners ... + * + * @param event: ENUM_XPOI_EVENTS member, Specified Occured Event ... + * @param param: XCBasePOI implementation, Specified Event Object ... + */ + void NotifyEventListeners( + ENUM_XPOI_EVENTS event, + XCBasePOI *param // + ) + { + // + int count = ArraySize(mEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mEventListeners[i]( + event, + param // + ); + } + } + + // + private: + // + + // + // Props ... + string mSymbol; // Market Symbol ... + ENUM_TIMEFRAMES mPeriod; // Market Period ... + XBarTracker mBarTracker; // Market Bar Tracker ... + XCBarAnalyser *mBarAnalyser; // Bar Analyser ... + + // + bool mLock; + + // + int mMaxRequiredPOIs; // Max Allowed Holds POI(s) ... + int maxAllowedLoopbackForInit; // Max Allowed Loopback for POI(s) Detection on Initialization Process ... + + // + TOnPOIEvent mEventListeners[]; // Event Listeners ... + + // + XCSwing *mSwings[]; // Holds Founded Swing ... + XCSwing *mSwingLows[]; // Holds Founded Swing Lows ... + XCSwing *mSwingHighs[]; // Holds Founded Swing Highs ... + int mSwingRange; // Swing Detection Range ... + + // + XCMomentumBar *mMomentumBars[]; // Holds Founded Momentum Bars ... + XCMomentumBar *mBullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ... + XCMomentumBar *mBearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ... + int mMomentumExtend; // Momentum Bar Detection Extends Range ... + double mMomentumBodyPercent; // Momentum Bar Detection Body Percent ... + + // + XCRejectionBar *mRejectionBars[]; // Holds Founded Rejection Bars ... + XCRejectionBar *mBullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ... + XCRejectionBar *mBearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ... + int mRejectionExtend; // Rejection Bar Detection Extends Range ... + double mRejectionShadowPercent; // Rejection Bar Detection Body Percent ... + + // + XCSupplyZone *mSupplyZones[]; // Holds Detected Supply Zones ... + XCDemandZone *mDemandZones[]; // Holds Detected Demand Zones ... + + // + int mSupResRange; // Support and Resistance Detection Range ... + bool mSupResRangeAsStart; // use Support and Resistance Range as Start ... + XCSupportZone *mSupportZones[]; // Holds Detected Support Zones ... + XCResistanceZone *mResistanceZones[]; // Holds Detected Resistance Zones ... + + // + XCFVG *mFairValueGaps[]; // Holds Founded FairValueGaps ... + XCFVG *mBullishFairValueGaps[]; // Holds Founded Bullish FairValueGaps ... + XCFVG *mBearishFairValueGaps[]; // Holds Founded Bearish FairValueGaps ... + int mFairValueGapSameBars; // FairValueGap Detection Same Bars ... + + // + XCOrderBlock *mOrderBlocks[]; // Holds Founded OrderBlocks ... + XCOrderBlock *mBullishOrderBlocks[]; // Holds Founded Bullish OrderBlocks ... + XCOrderBlock *mBearishOrderBlocks[]; // Holds Founded Bearish OrderBlocks ... + int mOrderBlockSameBars; // OrderBlock Detection Same Bars ... + + // + int mConsolidationZoneMinLoopback; // Minimum Length of Cnsolidation Zone ... + double mConsolidationZoneRangeInPoint; // Consolidation Zone Range in Point ... + XConsolidationZone mConsolidationZones[]; // Holds Founded Consolidation Zones ... + XConsolidationZone mBullishConsolidationZones[]; // Holds Founded Bullish Consolidation Zones ... + XConsolidationZone mBearishConsolidationZones[]; // Holds Founded Bearish Consolidation Zones ... + ENUM_APPLIED_PRICE mConsolidationZonesLowerAppliedTo; // Consolidation Zone Upper Applied To ... + ENUM_APPLIED_PRICE mConsolidationZonesUpperAppliedTo; // Consolidation Zone Lower Applied To ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.ex5 b/BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..6b8cbb3a8552c519d44e820d5dfac5ac102afdcd GIT binary patch literal 15212 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�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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.mq5 new file mode 100644 index 0000000..29c9f88 --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-poi.drawer.class.mq5 @@ -0,0 +1,4922 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOIDrawer +// Description: Provides Point of Interests +// Drawing Tools ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-cobject.class.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" + +// +// Definitions ... +class XCPOIDrawer : public XCBase +{ + // + public: + // + + // + // Constructor ... + void XCPOIDrawer() + { + // + Default(); + } + + // + // Deconstructor ... + void ~XCPOIDrawer() + { + // + Clean(mTicksZoneSpecs); + } + + // + // Setter Getter (s) ... + + /** + * Get Prefix ... + * + * @return ( string ) + */ + string Prefix() + { + return mPrefix; + } + + /** + * Set Prifx ... + * + * @param value: String ... + */ + void Prefix(string value) + { + mPrefix = value; + } + + /** + * Get Chart ID ... + * + * @return ( long ) + */ + long ChartIdentification() + { + return mChartIdentification; + } + + /** + * Set Chart ID ... + * + * @param value: Long ... + */ + void ChartIdentification(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartIdentification = value; + } + + /** + * Get SubWindow Id ... + * + * @return ( int ) + */ + int SubWindowIdentification() + { + return mSubWindowIdentification; + } + + /** + * Set SubWindow Id ... + * + * @param value: Integer ... + */ + void SubWindowIdentification(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSubWindowIdentification = value; + } + + // + // XOHCL ... + + /** + * Get Bar Width ... + * + * @return ( int ) + */ + int BarWidth() + { + return mBarWidth; + } + + /** + * Set Bar Width ... + * + * @param value: Integer ... + */ + void BarWidth(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mBarWidth = value; + } + + /** + * Get Bar Bullish Color ... + * + * @return ( color ) + */ + color BarBullishColor() + { + return mBarBullishColor; + } + + /** + * Set Bar Bullish Color ... + * + * @param value: Color ... + */ + void BarBullishColor(color value) + { + mBarBullishColor = value; + } + + /** + * Get Bar Bearish Color ... + * + * @return ( color ) + */ + color BarBearishColor() + { + return mBarBearishColor; + } + + /** + * Set Bar Bearish Color ... + * + * @param value: Color ... + */ + void BarBearishColor(color value) + { + mBarBearishColor = value; + } + + /** + * Get Fill Bar High Shadow State ... + * + * @return ( bool ) + */ + bool BarFillHighShadow() + { + return mBarFillHighShadow; + } + + /** + * Set Fill Bar High Shadow State ... + * + * @param value: Boolean ... + */ + void BarFillHighShadow(bool value) + { + mBarFillHighShadow = value; + } + + /** + * Get Bar High Shadow Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarHighShadowStyle() + { + return mBarHighShadowStyle; + } + + /** + * Set Bar High Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarHighShadowStyle(ENUM_LINE_STYLE value) + { + mBarHighShadowStyle = value; + } + + /** + * Get Fill Bar Body State ... + * + * @return ( bool ) + */ + bool BarFillBody() + { + return mBarFillBody; + } + + /** + * Set Fill Bar Body State ... + * + * @param value: Boolean ... + */ + void BarFillBody(bool value) + { + mBarFillBody = value; + } + + /** + * Get Bar Body Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarBodyStyle() + { + return mBarBodyStyle; + } + + /** + * Set Bar Body Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarBodyStyle(ENUM_LINE_STYLE value) + { + mBarBodyStyle = value; + } + + /** + * Get Fill Bar Low Show State ... + * + * @return ( bool ) + */ + bool BarFillLowShadow() + { + return mBarFillLowShadow; + } + + /** + * Set Fill Bar Low Show State ... + * + * @param value: Boolean ... + */ + void BarFillLowShadow(bool value) + { + mBarFillLowShadow = value; + } + + /** + * Get Bar Low Shadow Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarLowShadowStyle() + { + return mBarLowShadowStyle; + } + + /** + * Set Bar Low Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarLowShadowStyle(ENUM_LINE_STYLE value) + { + mBarLowShadowStyle = value; + } + + // + // Swing Low ... + + /** + * Get Swing Low Width ... + * + * @return ( int ) + */ + int SwingLowWidth() + { + return mSwingLowWidth; + } + + /** + * Set Swing Low Width ... + * + * @param value: Integer ... + */ + void SwingLowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingLowWidth = value; + } + + /** + * Get Swing Low Arrow Code ... + * + * @return ( int ) + */ + int SwingLowArrow() + { + return mSwingLowArrow; + } + + /** + * Set Swing Low Arrow Code ... + * + * @param value: Integer ... + */ + void SwingLowArrow(int value) + { + // + mSwingLowArrow = value; + } + + /** + * Get Swing Low Color ... + * + * @return ( color ) + */ + color SwingLowColor() + { + return mSwingLowColor; + } + + /** + * Set Swing Low Color ... + * + * @param value: Color ... + */ + void SwingLowColor(color value) + { + mSwingLowColor = value; + } + + // + // Swing High ... + + /** + * Get Swing High Width ... + * + * @return ( int ) + */ + int SwingHighWidth() + { + return mSwingHighWidth; + } + + /** + * Set Swing High Width ... + * + * @param value: Integer ... + */ + void SwingHighWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingHighWidth = value; + } + + /** + * Get Swing High Arrow Code ... + * + * @return ( int ) + */ + int SwingHighArrow() + { + return mSwingHighArrow; + } + + /** + * Set Swing High Arrow Code ... + * + * @param value: Integer ... + */ + void SwingHighArrow(int value) + { + // + mSwingHighArrow = value; + } + + /** + * Get Swing High Color ... + * + * @return ( color ) + */ + color SwingHighColor() + { + return mSwingHighColor; + } + + /** + * Set Swing High Color ... + * + * @param value: Color ... + */ + void SwingHighColor(color value) + { + mSwingHighColor = value; + } + + // + // Bullish Momentum Bar ... + + /** + * Get Bullish Momentum Bar Width ... + * + * @return ( int ) + */ + int BullishMomentumBarWidth() + { + return mBullishMomentumBarWidth; + } + + /** + * Set Bullish Momentum Bar Width ... + * + * @param value: Integer ... + */ + void BullishMomentumBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishMomentumBarWidth = value; + } + + /** + * Get Bullish Momentum Bar Arrow Code ... + * + * @return ( int ) + */ + int BullishMomentumBarArrow() + { + return mBullishMomentumBarArrow; + } + + /** + * Set Bullish Momentum Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BullishMomentumBarArrow(int value) + { + // + mBullishMomentumBarArrow = value; + } + + /** + * Get Bullish Momentum Bar Color ... + * + * @return ( color ) + */ + color BullishMomentumBarColor() + { + return mBullishMomentumBarColor; + } + + /** + * Set Bullish Momentum Bar Color ... + * + * @param value: Color ... + */ + void BullishMomentumBarColor(color value) + { + mBullishMomentumBarColor = value; + } + + // + // Bearish Momentum Bar ... + + /** + * Get Bearish Momentum Bar Width ... + * + * @return ( int ) + */ + int BearishMomentumBarWidth() + { + return mBearishMomentumBarWidth; + } + + /** + * Set Bearish Momentum Bar Width ... + * + * @param value: Integer ... + */ + void BearishMomentumBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishMomentumBarWidth = value; + } + + /** + * Get Bearish Momentum Bar Arrow Code ... + * + * @return ( int ) + */ + int BearishMomentumBarArrow() + { + return mBearishMomentumBarArrow; + } + + /** + * Set Bearish Momentum Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BearishMomentumBarArrow(int value) + { + // + mBearishMomentumBarArrow = value; + } + + /** + * Get Bearish Momentum Bar Color ... + * + * @return ( color ) + */ + color BearishMomentumBarColor() + { + return mBearishMomentumBarColor; + } + + /** + * Set Bearish Momentum Bar Color ... + * + * @param value: Color ... + */ + void BearishMomentumBarColor(color value) + { + mBearishMomentumBarColor = value; + } + + // + // Bullish Rejection Bar ... + + /** + * Get Bullish Rejection Bar Width ... + * + * @return ( int ) + */ + int BullishRejectionBarWidth() + { + return mBullishRejectionBarWidth; + } + + /** + * Set Bullish Rejection Bar Width ... + * + * @param value: Integer ... + */ + void BullishRejectionBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishRejectionBarWidth = value; + } + + /** + * Get Bullish Rejection Bar Arrow Code ... + * + * @return ( int ) + */ + int BullishRejectionBarArrow() + { + return mBullishRejectionBarArrow; + } + + /** + * Set Bullish Rejection Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BullishRejectionBarArrow(int value) + { + // + mBullishRejectionBarArrow = value; + } + + /** + * Get Bullish Rejection Bar Color ... + * + * @return ( color ) + */ + color BullishRejectionBarColor() + { + return mBullishRejectionBarColor; + } + + /** + * Set Bullish Rejection Bar Color ... + * + * @param value: Color ... + */ + void BullishRejectionBarColor(color value) + { + mBullishRejectionBarColor = value; + } + + // + // Bearish Rejection Bar ... + + /** + * Get Bearish Rejection Bar Width ... + * + * @return ( int ) + */ + int BearishRejectionBarWidth() + { + return mBearishRejectionBarWidth; + } + + /** + * Set Bearish Rejection Bar Width ... + * + * @param value: Integer ... + */ + void BearishRejectionBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishRejectionBarWidth = value; + } + + /** + * Get Bearish Rejection Bar Arrow Code ... + * + * @return ( int ) + */ + int BearishRejectionBarArrow() + { + return mBearishRejectionBarArrow; + } + + /** + * Set Bearish Rejection Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BearishRejectionBarArrow(int value) + { + // + mBearishRejectionBarArrow = value; + } + + /** + * Get Bearish Rejection Bar Color ... + * + * @return ( color ) + */ + color BearishRejectionBarColor() + { + return mBearishRejectionBarColor; + } + + /** + * Set Bearish Rejection Bar Color ... + * + * @param value: Color ... + */ + void BearishRejectionBarColor(color value) + { + mBearishRejectionBarColor = value; + } + + // + // Supply Zone ... + + /** + * Get Fill Supply Zone ... + * + * @return ( bool ) + */ + bool SupplyZoneFill() + { + return mSupplyZoneFill; + } + + /** + * Set Fill Supply Zone ... + * + * @param value: Boolean ... + */ + void SupplyZoneFill(bool value) + { + mSupplyZoneFill = value; + } + + /** + * Get Supply Zone Width ... + * + * @return ( int ) + */ + int SupplyZoneWidth() + { + return mSupplyZoneWidth; + } + + /** + * Set Supply Zone Width ... + * + * @param value: Integer ... + */ + void SupplyZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSupplyZoneWidth = value; + } + + /** + * Get Supply Zone Color ... + * + * @return ( color ) + */ + color SupplyZoneColor() + { + return mSupplyZoneColor; + } + + /** + * Set Supply Zone Color ... + * + * @param value: Color ... + */ + void SupplyZoneColor(color value) + { + mSupplyZoneColor = value; + } + + /** + * Get Supply Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE SupplyZoneStyle() + { + return mSupplyZoneStyle; + } + + /** + * Set Supply Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void SupplyZoneStyle(ENUM_LINE_STYLE value) + { + mSupplyZoneStyle = value; + } + + // + // Demand Zone ... + + /** + * Get Fill Demand Zone ... + * + * @return ( bool ) + */ + bool DemandZoneFill() + { + return mDemandZoneFill; + } + + /** + * Set Fill Demand Zone ... + * + * @param value: Boolean ... + */ + void DemandZoneFill(bool value) + { + mDemandZoneFill = value; + } + + /** + * Get Demand Zone Width ... + * + * @return ( int ) + */ + int DemandZoneWidth() + { + return mDemandZoneWidth; + } + + /** + * Set Demand Zone Width ... + * + * @param value: Integer ... + */ + void DemandZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mDemandZoneWidth = value; + } + + /** + * Get Demand Zone Color ... + * + * @return ( color ) + */ + color DemandZoneColor() + { + return mDemandZoneColor; + } + + /** + * Set Demand Zone Color ... + * + * @param value: Color ... + */ + void DemandZoneColor(color value) + { + mDemandZoneColor = value; + } + + /** + * Get Demand Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE DemandZoneStyle() + { + return mDemandZoneStyle; + } + + /** + * Set Demand Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void DemandZoneStyle(ENUM_LINE_STYLE value) + { + mDemandZoneStyle = value; + } + + // + // Resistance Zone ... + + /** + * Get Fill Resistance Zone ... + * + * @return ( bool ) + */ + bool ResistanceZoneFill() + { + return mResistanceZoneFill; + } + + /** + * Set Fill Resistance Zone ... + * + * @param value: Boolean ... + */ + void ResistanceZoneFill(bool value) + { + mResistanceZoneFill = value; + } + + /** + * Get Resistance Zone Width ... + * + * @return ( int ) + */ + int ResistanceZoneWidth() + { + return mResistanceZoneWidth; + } + + /** + * Set Resistance Zone Width ... + * + * @param value: Integer ... + */ + void ResistanceZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mResistanceZoneWidth = value; + } + + /** + * Get Resistance Zone Color ... + * + * @return ( color ) + */ + color ResistanceZoneColor() + { + return mResistanceZoneColor; + } + + /** + * Set Resistance Zone Color ... + * + * @param value: Color ... + */ + void ResistanceZoneColor(color value) + { + mResistanceZoneColor = value; + } + + /** + * Get Resistance Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE ResistanceZoneStyle() + { + return mResistanceZoneStyle; + } + + /** + * Set Resistance Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ResistanceZoneStyle(ENUM_LINE_STYLE value) + { + mResistanceZoneStyle = value; + } + + // + // Support Zone ... + + /** + * Get Fill Support Zone ... + * + * @return ( bool ) + */ + bool SupportZoneFill() + { + return mSupportZoneFill; + } + + /** + * Set Fill Support Zone ... + * + * @param value: Boolean ... + */ + void SupportZoneFill(bool value) + { + mSupportZoneFill = value; + } + + /** + * Get Support Zone Width ... + * + * @return ( int ) + */ + int SupportZoneWidth() + { + return mSupportZoneWidth; + } + + /** + * Set Support Zone Width ... + * + * @param value: Integer ... + */ + void SupportZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSupportZoneWidth = value; + } + + /** + * Get Support Zone Color ... + * + * @return ( color ) + */ + color SupportZoneColor() + { + return mSupportZoneColor; + } + + /** + * Set Support Zone Color ... + * + * @param value: Color ... + */ + void SupportZoneColor(color value) + { + mSupportZoneColor = value; + } + + /** + * Get Support Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE SupportZoneStyle() + { + return mSupportZoneStyle; + } + + /** + * Set Support Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void SupportZoneStyle(ENUM_LINE_STYLE value) + { + mSupportZoneStyle = value; + } + + // + // Bullish Order Block ... + + /** + * Get Fill Bullish Order Block ... + * + * @return ( bool ) + */ + bool BullishOrderBlockFill() + { + return mBullishOrderBlockFill; + } + + /** + * Set Fill Bullish Order Block ... + * + * @param value: Boolean ... + */ + void BullishOrderBlockFill(bool value) + { + mBullishOrderBlockFill = value; + } + + /** + * Get Bullish Order Block Width ... + * + * @return ( int ) + */ + int BullishOrderBlockWidth() + { + return mBullishOrderBlockWidth; + } + + /** + * Set Bullish Order Block Width ... + * + * @param value: Integer ... + */ + void BullishOrderBlockWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishOrderBlockWidth = value; + } + + /** + * Get Bullish Order Block Color ... + * + * @return ( color ) + */ + color BullishOrderBlockColor() + { + return mBullishOrderBlockColor; + } + + /** + * Set Bullish Order Block Color ... + * + * @param value: Color ... + */ + void BullishOrderBlockColor(color value) + { + mBullishOrderBlockColor = value; + } + + /** + * Get Bullish Order Block Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BullishOrderBlockStyle() + { + return mBullishOrderBlockStyle; + } + + /** + * Set Bullish Order Block Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BullishOrderBlockStyle(ENUM_LINE_STYLE value) + { + mBullishOrderBlockStyle = value; + } + + // + // Bearish Order Block ... + + /** + * Get Fill Bearish Order Block ... + * + * @return ( bool ) + */ + bool BearishOrderBlockFill() + { + return mBearishOrderBlockFill; + } + + /** + * Set Fill Bearish Order Block ... + * + * @param value: Boolean ... + */ + void BearishOrderBlockFill(bool value) + { + mBearishOrderBlockFill = value; + } + + /** + * Get Bearish Order Block Width ... + * + * @return ( int ) + */ + int BearishOrderBlockWidth() + { + return mBearishOrderBlockWidth; + } + + /** + * Set Bearish Order Block Width ... + * + * @param value: Integer ... + */ + void BearishOrderBlockWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishOrderBlockWidth = value; + } + + /** + * Get Bearish Order Block Color ... + * + * @return ( color ) + */ + color BearishOrderBlockColor() + { + return mBearishOrderBlockColor; + } + + /** + * Set Bearish Order Block Color ... + * + * @param value: Color ... + */ + void BearishOrderBlockColor(color value) + { + mBearishOrderBlockColor = value; + } + + /** + * Get Bearish Order Block Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BearishOrderBlockStyle() + { + return mBearishOrderBlockStyle; + } + + /** + * Set Bearish Order Block Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BearishOrderBlockStyle(ENUM_LINE_STYLE value) + { + mBearishOrderBlockStyle = value; + } + + // + // Bullish FVG ... + + /** + * Get Fill Bullish FVG ... + * + * @return ( bool ) + */ + bool BullishFVGFill() + { + return mBullishFVGFill; + } + + /** + * Set Fill Bullish FVG ... + * + * @param value: Boolean ... + */ + void BullishFVGFill(bool value) + { + mBullishFVGFill = value; + } + + /** + * Get Bullish FVG Width ... + * + * @return ( int ) + */ + int BullishFVGWidth() + { + return mBullishFVGWidth; + } + + /** + * Set Bullish FVG Width ... + * + * @param value: Integer ... + */ + void BullishFVGWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishFVGWidth = value; + } + + /** + * Get Bullish FVG Color ... + * + * @return ( color ) + */ + color BullishFVGColor() + { + return mBullishFVGColor; + } + + /** + * Set Bullish FVG Color ... + * + * @param value: Color ... + */ + void BullishFVGColor(color value) + { + mBullishFVGColor = value; + } + + /** + * Get Bullish FVG Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BullishFVGStyle() + { + return mBullishFVGStyle; + } + + /** + * Set Bullish FVG Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BullishFVGStyle(ENUM_LINE_STYLE value) + { + mBullishFVGStyle = value; + } + + // + // Bearish FVG ... + + /** + * Get Fill Bearish FVG ... + * + * @return ( bool ) + */ + bool BearishFVGFill() + { + return mBearishFVGFill; + } + + /** + * Set Fill Bearish FVG ... + * + * @param value: Boolean ... + */ + void BearishFVGFill(bool value) + { + mBearishFVGFill = value; + } + + /** + * Get Bearish FVG Width ... + * + * @return ( int ) + */ + int BearishFVGWidth() + { + return mBearishFVGWidth; + } + + /** + * Set Bearish FVG Width ... + * + * @param value: Integer ... + */ + void BearishFVGWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishFVGWidth = value; + } + + /** + * Get Bearish FVG Color ... + * + * @return ( color ) + */ + color BearishFVGColor() + { + return mBearishFVGColor; + } + + /** + * Set Bearish FVG Color ... + * + * @param value: Color ... + */ + void BearishFVGColor(color value) + { + mBearishFVGColor = value; + } + + /** + * Get Bearish FVG Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BearishFVGStyle() + { + return mBearishFVGStyle; + } + + /** + * Set Bearish FVG Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BearishFVGStyle(ENUM_LINE_STYLE value) + { + mBearishFVGStyle = value; + } + + // + // Virtuals ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Apply Default Props ... + + // + Prefix(NULL); + ChartIdentification(0); + SubWindowIdentification(0); + + // + BarWidth(1); + BarBearishColor(clrRed); + BarBullishColor(clrLime); + BarFillBody(false); + BarFillHighShadow(false); + BarFillLowShadow(false); + BarBodyStyle(STYLE_DOT); + BarLowShadowStyle(STYLE_DOT); + BarHighShadowStyle(STYLE_DOT); + + // + int arrowWidth = 1; + + // + SwingLowArrow(108); + SwingLowColor(clrAqua); + SwingLowWidth(arrowWidth); + + // + SwingHighArrow(108); + SwingHighWidth(arrowWidth); + SwingHighColor(clrMagenta); + + // + arrowWidth++; + + // + BullishMomentumBarArrow(225); + BullishMomentumBarWidth(arrowWidth); + BullishMomentumBarColor(clrAqua); + + // + BearishMomentumBarArrow(226); + BearishMomentumBarWidth(arrowWidth); + BearishMomentumBarColor(clrMagenta); + + // + arrowWidth++; + + // + BullishRejectionBarArrow(217); + BullishRejectionBarWidth(arrowWidth); + BullishRejectionBarColor(clrAqua); + + // + BearishRejectionBarArrow(218); + BearishRejectionBarWidth(arrowWidth); + BearishRejectionBarColor(clrMagenta); + + // + SupportZoneFill(false); + SupportZoneWidth(1); + SupportZoneStyle(STYLE_DOT); + SupportZoneColor(clrLime); + + // + ResistanceZoneFill(false); + ResistanceZoneWidth(1); + ResistanceZoneStyle(STYLE_DOT); + ResistanceZoneColor(clrRed); + + // + SupplyZoneFill(false); + SupplyZoneWidth(1); + SupplyZoneStyle(STYLE_DOT); + SupplyZoneColor(clrRed); + + // + DemandZoneFill(false); + DemandZoneWidth(1); + DemandZoneStyle(STYLE_DOT); + DemandZoneColor(clrGreen); + + // + BullishOrderBlockFill(false); + BullishOrderBlockWidth(1); + BullishOrderBlockStyle(STYLE_DASHDOT); + BullishOrderBlockColor(clrLime); + + // + BearishOrderBlockFill(false); + BearishOrderBlockWidth(1); + BearishOrderBlockStyle(STYLE_DASHDOT); + BearishOrderBlockColor(clrRed); + + // + BullishFVGFill(false); + BullishFVGWidth(1); + BullishFVGStyle(STYLE_DOT); + BullishFVGColor(clrLime); + + // + BearishFVGFill(false); + BearishFVGWidth(1); + BearishFVGStyle(STYLE_DOT); + BearishFVGColor(clrRed); + + // + // Add Default TickZone Specs ... + bool isSpecsInited = false; + bool fillTickZone = false; + XTickZoneLevelSpecs specs10; + isSpecsInited = specs10.Init( + 10, + clrWhite, + clrWhite, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs10); + } + + // + XTickZoneLevelSpecs specs20; + isSpecsInited = specs20.Init( + 20, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs20); + } + + // + XTickZoneLevelSpecs specs30; + isSpecsInited = specs30.Init( + 30, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs30); + } + + // + XTickZoneLevelSpecs specs40; + isSpecsInited = specs40.Init( + 40, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs40); + } + + // + XTickZoneLevelSpecs specs50; + isSpecsInited = specs50.Init( + 50, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs50); + } + + // + XTickZoneLevelSpecs specs60; + isSpecsInited = specs60.Init( + 60, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs60); + } + + // + XTickZoneLevelSpecs specs70; + isSpecsInited = specs70.Init( + 70, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs70); + } + + // + XTickZoneLevelSpecs specs80; + isSpecsInited = specs80.Init( + 80, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs80); + } + + // + XTickZoneLevelSpecs specs90; + isSpecsInited = specs90.Init( + 90, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs90); + } + + // + XTickZoneLevelSpecs specs100; + isSpecsInited = specs100.Init( + 100, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs100); + } + + // + } + + // + // Object Creators ... + + // + // Swings ... + + /** + * Create Swing High Object ... + * + * @param swing: XCSwing instance ... + * @param object: XCSwingHighObject pointer ... + * + * @return ( bool ) + */ + bool CreateSwingHigh( + XCSwing &swing, + XCSwingHighObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + swing.IsValid() && + swing.IsSwingHigh(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = SwingHighArrow(); + int width = SwingHighWidth(); + color crl = SwingHighColor(); + + // + object = new XCSwingHighObject(); + result = object.Create( + chartID, + window, + arrow, + swing, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + /** + * Create Swing Low Object ... + * + * @param swing: XCSwing instance ... + * @param object: XCSwingLowObject pointer ... + * + * @return ( bool ) + */ + bool CreateSwingLow( + XCSwing &swing, + XCSwingLowObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + swing.IsValid() && + swing.IsSwingLow(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = SwingLowArrow(); + int width = SwingLowWidth(); + color crl = SwingLowColor(); + + // + object = new XCSwingLowObject(); + result = object.Create( + chartID, + window, + arrow, + swing, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + // + // Momentum Bars ... + + /** + * Create Bullish Momentum Bar Object ... + * + * @param momentumBar: XCMomentumBar instance ... + * @param object: XCBullishMomentumObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishMomentumBar( + XCMomentumBar &momentumBar, + XCBullishMomentumBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + momentumBar.IsValid() && + momentumBar.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BullishMomentumBarArrow(); + int width = BullishMomentumBarWidth(); + color crl = BullishMomentumBarColor(); + + // + object = new XCBullishMomentumBarObject(); + result = object.Create( + chartID, + window, + arrow, + momentumBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + /** + * Create Bearish Momentum Bar Object ... + * + * @param momentumBar: XCMomentumBar instance ... + * @param object: XCBearishMomentumObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishMomentumBar( + XCMomentumBar &momentumBar, + XCBearishMomentumBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + momentumBar.IsValid() && + momentumBar.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BearishMomentumBarArrow(); + int width = BearishMomentumBarWidth(); + color crl = BearishMomentumBarColor(); + + // + object = new XCBearishMomentumBarObject(); + result = object.Create( + chartID, + window, + arrow, + momentumBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + // + // Rejection Bars ... + + /** + * Create Bullish Rejection Bar Object ... + * + * @param momentumBar: XCRejectionBar instance ... + * @param object: XCBullishRejectionObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishRejectionBar( + XCRejectionBar &rejectionBar, + XCBullishRejectionBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + rejectionBar.IsValid() && + rejectionBar.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BullishRejectionBarArrow(); + int width = BullishRejectionBarWidth(); + color crl = BullishRejectionBarColor(); + + // + object = new XCBullishRejectionBarObject(); + result = object.Create( + chartID, + window, + arrow, + rejectionBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + /** + * Create Bearish Rejection Bar Object ... + * + * @param rejectionBar: XCRejectionBar instance ... + * @param object: XCBearishRejectionObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishRejectionBar( + XCRejectionBar &rejectionBar, + XCBearishRejectionBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + rejectionBar.IsValid() && + rejectionBar.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BearishRejectionBarArrow(); + int width = BearishRejectionBarWidth(); + color crl = BearishRejectionBarColor(); + + // + object = new XCBearishRejectionBarObject(); + result = object.Create( + chartID, + window, + arrow, + rejectionBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + // + // Support and Resistance ... + + /** + * Create Support Object ... + * + * @param zone: XCSupportZone instance ... + * @param object: XCSupportZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateSupportZone( + XCSupportZone &zone, + XCSupportZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = SupportZoneFill(); + int width = SupportZoneWidth(); + color crl = SupportZoneColor(); + ENUM_LINE_STYLE style = SupportZoneStyle(); + + // + object = new XCSupportZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Resistance Object ... + * + * @param zone: XCResistanceZone instance ... + * @param object: XCResistanceZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateResistanceZone( + XCResistanceZone &zone, + XCResistanceZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = ResistanceZoneFill(); + int width = ResistanceZoneWidth(); + color crl = ResistanceZoneColor(); + ENUM_LINE_STYLE style = ResistanceZoneStyle(); + + // + object = new XCResistanceZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Supply and Demand Zones ... + + /** + * Create Supply Object ... + * + * @param zone: XCSupplyZone instance ... + * @param object: XCSupplyZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateSupplyZone( + XCSupplyZone &zone, + XCSupplyZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = SupplyZoneFill(); + int width = SupplyZoneWidth(); + color crl = SupplyZoneColor(); + ENUM_LINE_STYLE style = SupplyZoneStyle(); + + // + object = new XCSupplyZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Demand Object ... + * + * @param zone: XCDemandZone instance ... + * @param object: XCDemandZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateDemandZone( + XCDemandZone &zone, + XCDemandZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = DemandZoneFill(); + int width = DemandZoneWidth(); + color crl = DemandZoneColor(); + ENUM_LINE_STYLE style = DemandZoneStyle(); + + // + object = new XCDemandZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Order Blocks ... + + /** + * Create Bullish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBullishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishOrderBlock( + XCOrderBlock &zone, + XCBullishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BullishOrderBlockFill(); + int width = BullishOrderBlockWidth(); + color crl = BullishOrderBlockColor(); + ENUM_LINE_STYLE style = BullishOrderBlockStyle(); + + // + object = new XCBullishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Bearish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBearishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishOrderBlock( + XCOrderBlock &zone, + XCBearishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BearishOrderBlockFill(); + int width = BearishOrderBlockWidth(); + color crl = BearishOrderBlockColor(); + ENUM_LINE_STYLE style = BearishOrderBlockStyle(); + + // + object = new XCBearishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + bool CreateOrderBlock( + XCOrderBlock &zone, + XCBaseObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = zone.IsBullish(); + if (isBullish) + { + // + XCBullishOrderBlockObject *iObj; + result = CreateBullishOrderBlock( + zone, + iObj // + ); + if (result) + { + object = (XCBaseObject *)iObj; + } + } + else + { + // + XCBearishOrderBlockObject *iObj; + result = CreateBearishOrderBlock( + zone, + iObj // + ); + if (result) + { + object = (XCBaseObject *)iObj; + } + } + + // + return result; + } + + // + // Fair Value Gaps ... + + /** + * Create Bullish Fair Value Gap Object ... + * + * @param zone: XCFVG instance ... + * @param object: XCBullishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishFairValueGap( + XCFVG &zone, + XCBullishFairValueGapObject *&object // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BullishFVGFill(); + int width = BullishFVGWidth(); + color crl = BullishFVGColor(); + ENUM_LINE_STYLE style = BullishFVGStyle(); + + // + object = new XCBullishFairValueGapObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Bearish Fair Value Gap Object ... + * + * @param zone: XCFVG instance ... + * @param object: XCBearishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishFairValueGap( + XCFVG &zone, + XCBearishFairValueGapObject *&object // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BearishFVGFill(); + int width = BearishFVGWidth(); + color crl = BearishFVGColor(); + ENUM_LINE_STYLE style = BearishFVGStyle(); + + // + object = new XCBearishFairValueGapObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + bool CreateFairValueGap( + XCFVG &zone, + XCBaseObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = zone.IsBullish(); + if (isBullish) + { + // + XCBullishFairValueGapObject *iObj; + result = CreateBullishFairValueGap( + zone, + iObj // + ); + if (result) + { + object = (XCBaseObject *)iObj; + } + } + else + { + // + XCBearishFairValueGapObject *iObj; + result = CreateBearishFairValueGap( + zone, + iObj // + ); + if (result) + { + object = (XCBaseObject *)iObj; + } + } + + // + return result; + } + + // + // Ticks Zone ... + + /** + * Add Tick Zone Draw Specifications ... + * + * @param specs: XTickZoneLevelSpecs instance ... + */ + void AddTickZoneLevelSpecs( + XTickZoneLevelSpecs &specs // + ) + { + // + if (!specs.IsValid()) + { + return; + } + + // + bool isExists = false; + int count = ArraySize(mTicksZoneSpecs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XTickZoneLevelSpecs iSpec = mTicksZoneSpecs[i]; + + // + isExists = specs.percent == iSpec.percent; + if (isExists) + { + break; + } + } + } + if (isExists) + { + return; + } + + // + AddRef( + specs, + mTicksZoneSpecs // + ); + } + + /** + * Draw Specified Ticker Zone ... + * + * @param zone: XCTicksZone instance Specified Ticker Zone ... + * @param object: XCTicksZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateTicksZone( + XCTicksZone &zone, + XCTicksZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCTicksZoneObject(); + result = object.Create( + chartID, + window, + zone, + mTicksZoneSpecs, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Create Trend Line Object ... + * + * @param swings: XSwingPoint instance Collection ... + * + * @return ( bool ) + */ + bool CreateTrend( + XSwingPoint &swings[], + XCTrendObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = ArraySize(swings) >= 2 && + IsValidSize(ArraySize(swings)); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCTrendObject(); + result = object.Create( + chartID, + window, + swings, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + color clrTrend = swings[0].type == X_SWING_LOW + ? SwingLowColor() + : SwingHighColor(); + object.TrendColor(clrTrend); + object.TrendRayRight(true); + + // + return result; + } + + /** + * Create Trend Line Object ... + * + * @param swings: XSwingPoint instance Collection ... + * @param useMinAsStart: Specified Min Value as Start ... + * + * @return ( bool ) + */ + bool CreateTrend( + XPoint &swings[], + XCTrendObject *&object, + bool useMinAsStart = true // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = ArraySize(swings) >= 2 && + IsValidSize(ArraySize(swings)); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCTrendObject(); + result = object.Create( + chartID, + window, + swings, + useMinAsStart, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + color clrTrend = useMinAsStart + ? SwingLowColor() + : SwingHighColor(); + object.TrendColor(clrTrend); + object.TrendRayRight(true); + + // + return result; + } + + /** + * Create Consolidation Zone Object ... + * + * @param zone: XConsolidationZone instance Reference ... + * + * @return ( bool ) + */ + bool CreateConsolidationZone( + XConsolidationZone &zone, + XCConsolidationZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + color czColor = IsBullish(zone.dir) + ? BarBullishColor() + : BarBearishColor(); + + // + object = new XCConsolidationZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (result) + { + object.ZoneColor(czColor); + } + + // + return result; + } + + /** + * Create Bar Object ... + * + * @param bar: XOHCL instance Reference ... + * @param object: XCOHCLObject pointer Reference .. + * @param to: Datetime ... + * + * @return ( bool ) + */ + bool CreateBar( + XOHCL &bar, + XCOHCLObject *&object, + datetime to = NULL // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + to = NormalizeTime(to); + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int width = BarWidth(); + + // + color mBullishColor = BarBullishColor(); + color mBearishColor = BarBearishColor(); + + // + bool fillBody = BarFillBody(); + bool fillHighShadow = BarFillHighShadow(); + bool fillLowShadow = BarFillLowShadow(); + + // + ENUM_LINE_STYLE bodyStyle = BarBodyStyle(); + ENUM_LINE_STYLE highShadowStyle = BarHighShadowStyle(); + ENUM_LINE_STYLE lowShadowStyle = BarLowShadowStyle(); + + // + object = new XCOHCLObject(); + result = object.Create( + chartID, + window, + bar, + to, + prefix // + ); + if (result) + { + // + // Apply Styling ... + + // + object.BodyWidth(width); + object.LowShadowWidth(width); + object.HighShadowWidth(width); + + // + object.BodyStyle(bodyStyle); + object.LowShadowStyle(lowShadowStyle); + object.HighShadowStyle(highShadowStyle); + + // + bool isBullish = bar.IsBullish(); + if (isBullish) + { + // + object.BodyColor(mBullishColor); + object.LowShadowColor(mBullishColor); + object.HighShadowColor(mBullishColor); + } + else + { + // + object.BodyColor(mBearishColor); + object.LowShadowColor(mBearishColor); + object.HighShadowColor(mBearishColor); + } + + // + object.BodyFill(fillBody); + object.HighShadowFill(fillHighShadow); + object.LowShadowFill(fillLowShadow); + } + + // + return result; + } + + /** + * Create Bar Arrow Object ... + * + * @param bar: XOHCL instance Reference ... + * @param priceType: ENUM_X_PRICE member ... + * @param arrow: int, Arrow Code ... + * @param clr: color, Arro Color ... + * @param width: int, Arrow Width ... + * @param anchor: ENUM_ARROW_ANCHOR, anchor of Arrow ... + * @param name: string, name of Arrow ... + * + * @return ( bool ) + */ + bool CreateBarArrow( + XOHCL &bar, + XCBarArrowObject *&object, + ENUM_X_PRICE priceType, + int arrow = 159, + color clr = clrYellow, + int width = 3, + ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, + string name = NULL // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + string barTag = bar.GetTag(name); + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + color mBullishColor = BarBullishColor(); + color mBearishColor = BarBearishColor(); + + // + prefix = + (IsValid(prefix) + ? prefix + "_" + : prefix) + + barTag; + + // + object = new XCBarArrowObject(); + result = object + .CreateByBar( + chartID, + prefix, + window, + arrow, + bar, + priceType // + ); + if (result) + { + // + object.ArrowColor(clr); + object.ArrowWidth(width); + } + + // + return result; + } + + /** + * Create Specific Box on Chart ... + * + * @param upper: Double ... + * @param lower: Double ... + * @param from: Datetime ... + * @param to: Datetime ... + * @param clr: Color ... + * @param width: Integer ... + * @param fill: Boolean ... + * @param style: ENUM_LINE_STYLE member ... + * + * @return ( bool ) + */ + bool CreateBox( + XCBoxObject *&object, + string name, + double upper, + double lower, + datetime from, + datetime to, + color clr = clrYellowGreen, + int width = 1, + bool fill = false, + ENUM_LINE_STYLE style = STYLE_SOLID // + ) + { + // + bool result = false; + + // + object = NULL; + + // + to = NormalizeTime(to); + + // + string dateStr = ToFormatString(from) + "|" + ToFormatString(to); + string dateMD5 = ToMD5(dateStr); + if (!IsValid(name)) + { + // + name = "XBox_" + + ToString(upper) + "_" + + ToString(lower) + "_" + + dateMD5; + } + + // + result = + upper > 0 && + lower > 0 && + to > from && + IsValid(to) && + IsValid(name) && + IsValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCBoxObject(); + result = object.Create( + chartID, + window, + name, + upper, + lower, + from, + to, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.BoxColor(clr); + object.BoxFill(fill); + object.BoxWidth(width); + object.BoxStyle(style); + + // + return result; + } + + /** + * Create Specific Box on Chart ... + * + * @param box: XBoxZone instance Reference ... + * @param clr: Color ... + * @param width: Integer ... + * @param fill: Boolean ... + * @param style: ENUM_LINE_STYLE member ... + * + * @return ( bool ) + */ + bool DrawBox( + XBoxZone &box, + XCBoxObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int width = 1; + bool fill = false; + color clr = + box.IsBullish() + ? BullishFVGColor() + : BearishFVGColor(); + ENUM_LINE_STYLE style = STYLE_DASHDOTDOT; + string name = box.GetTag(); + + // + result = CreateBox( + object, + name, + box.upper, + box.lower, + box.from, + box.to, + clr, + width, + fill, + style // + ); + + // + return result; + } + + /** + * Create Specific Box on Chart ... + * + * @param box: XBoxZone instance Reference ... + * @param clr: Color ... + * @param width: Integer ... + * @param fill: Boolean ... + * @param style: ENUM_LINE_STYLE member ... + * + * @return ( bool ) + */ + bool CreateBox( + XBoxZone &box, + XCBoxObject *&object, + color clr = clrYellowGreen, + int width = 1, + bool fill = false, + ENUM_LINE_STYLE style = STYLE_SOLID // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + string name = box.GetTag(); + + // + result = CreateBox( + object, + name, + box.upper, + box.lower, + box.from, + box.to, + clr, + width, + fill, + style // + ); + + // + return result; + } + + /** + * Create Specific Risk Reward (RR) on Chart ... + * + * @param rr: XRR instance Reference ... + * + * @return ( bool ) + */ + bool CreateRR( + XRR &rr, + XCRRObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = rr.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCRRObject(); + result = object.Create( + chartID, + window, + rr, + prefix // + ); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Draw Specified Signal ... + * + * @param signal: XSignal instance ... + */ + bool DrawSignal( + XSignal &signal, + XCSignalObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCSignalObject(); + result = object.Create( + chartID, + window, + signal, + prefix // + ); + if (!result) + { + return result; + } + + // + object.TPWidth(1); + object.TPColor(clrGreen); + object.TPWidth(STYLE_DOT); + + // + object.SLWidth(1); + object.SLColor(clrRed); + object.SLWidth(STYLE_DOT); + + // + object.TargetWidth(1); + object.TargetColor(clrLightBlue); + object.TargetWidth(STYLE_DOT); + + // + object.EntryWidth(1); + object.EntryColor(clrYellow); + object.EntryWidth(STYLE_DOT); + + // + return result; + } + + /** + * Draw Specified POI State ... + * + * @param state: XPOIState instance Reference ... + * @param drawnObjects: CArrayObj instance for Holding Drawn Objects ... + * @param drawTicksZone: Boolean ... + * @param ignoreSwingHighs: Boolean ... + * @param ignoreSwingLows: Boolean ... + * @param ignoreSupportZones: Boolean ... + * @param ignoreResistanceZones: Boolean ... + * @param ignoreSupplyZones: Boolean ... + * @param ignoreDemandZones: Boolean ... + * @param ignoreBullishOrderBlocks: Boolean ... + * @param ignoreBearishOrderBlocks: Boolean ... + * @param ignoreBullishFairValueGaps: Boolean ... + * @param ignoreBearishFairValueGaps: Boolean ... + * @param ignoreBullishRejectionBars: Boolean ... + * @param ignoreBearishRejectionBars: Boolean ... + * @param ignoreBullishMomentumBars: Boolean ... + * @param ignoreBearishMomentumBars: Boolean ... + */ + int DrawState( + XPOIState &state, + XCBaseObject *&drawnObjects[], + bool drawTicksZone = false, + bool ignoreSwingHighs = false, + bool ignoreSwingLows = false, + bool ignoreSupportZones = false, + bool ignoreResistanceZones = false, + bool ignoreSupplyZones = false, + bool ignoreDemandZones = false, + bool ignoreBullishOrderBlocks = false, + bool ignoreBearishOrderBlocks = false, + bool ignoreBullishFairValueGaps = false, + bool ignoreBearishFairValueGaps = false, + bool ignoreBullishRejectionBars = false, + bool ignoreBearishRejectionBars = false, + bool ignoreBullishMomentumBars = false, + bool ignoreBearishMomentumBars = false, + bool ignoreBullishConsolidationZones = false, + bool ignoreBearishConsolidationZones = false // + ) + { + // + int result = 0; + + // + if (!state.IsValid() || + !state.HasChild()) + { + return result; + } + + // + Clean(drawnObjects); + + // + // SwingHighs ... + if (!ignoreSwingHighs) + { + // + int count = state.CountSwingHighs(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = state.swingHighs[i]; + XCSwingHighObject *iObj; + + // + bool isCreated = CreateSwingHigh( + iSwing, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SwingLows ... + if (!ignoreSwingLows) + { + // + int count = state.CountSwingLows(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = state.swingLows[i]; + XCSwingLowObject *iObj; + + // + bool isCreated = CreateSwingLow( + iSwing, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SupportZones ... + if (!ignoreSupportZones) + { + // + int count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = state.supportZones[i]; + XCSupportZoneObject *iObj; + + // + bool isCreated = CreateSupportZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // ResistanceZones ... + if (!ignoreResistanceZones) + { + // + int count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = state.resistanceZones[i]; + XCResistanceZoneObject *iObj; + + // + bool isCreated = CreateResistanceZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SupplyZones ... + if (!ignoreSupplyZones) + { + // + int count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = state.supplyZones[i]; + XCSupplyZoneObject *iObj; + + // + bool isCreated = CreateSupplyZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // DemandZones ... + if (!ignoreDemandZones) + { + // + int count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = state.demandZones[i]; + XCDemandZoneObject *iObj; + + // + bool isCreated = CreateDemandZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishOrderBlocks ... + if (!ignoreBullishOrderBlocks) + { + // + int count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = state.bullishOrderBlocks[i]; + XCBullishOrderBlockObject *iObj; + + // + bool isCreated = CreateBullishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishOrderBlocks ... + if (!ignoreBearishOrderBlocks) + { + // + int count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = state.bearishOrderBlocks[i]; + XCBearishOrderBlockObject *iObj; + + // + bool isCreated = CreateBearishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishFairValueGaps ... + if (!ignoreBullishFairValueGaps) + { + // + int count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = state.bullishFairValueGaps[i]; + XCBullishFairValueGapObject *iObj; + + // + bool isCreated = CreateBullishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishFairValueGaps ... + if (!ignoreBearishFairValueGaps) + { + // + int count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = state.bearishFairValueGaps[i]; + XCBearishFairValueGapObject *iObj; + + // + bool isCreated = CreateBearishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishRejectionBars ... + if (!ignoreBullishRejectionBars) + { + // + int count = state.CountBullishRejectionBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = state.bullishRejectionBars[i]; + XCBullishRejectionBarObject *iObj; + + // + bool isCreated = CreateBullishRejectionBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishRejectionBars ... + if (!ignoreBearishRejectionBars) + { + // + int count = state.CountBearishRejectionBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = state.bearishRejectionBars[i]; + XCBearishRejectionBarObject *iObj; + + // + bool isCreated = CreateBearishRejectionBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishMomentumBars ... + if (!ignoreBullishMomentumBars) + { + // + int count = state.CountBullishMomentumBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iBar = state.bullishMomentumBars[i]; + XCBullishMomentumBarObject *iObj; + + // + bool isCreated = CreateBullishMomentumBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishMomentumBars ... + if (!ignoreBearishMomentumBars) + { + // + int count = state.CountBearishMomentumBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iBar = state.bearishMomentumBars[i]; + XCBearishMomentumBarObject *iObj; + + // + bool isCreated = CreateBearishMomentumBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // Bullish Consolidation Zones ... + if (!ignoreBullishConsolidationZones) + { + // + int count = state.CountBullishConsolidationZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCConsolidationZoneObject *iObj; + bool isCreated = CreateConsolidationZone( + state.bullishConsolidationZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // Bearish Consolidation Zones ... + if (!ignoreBearishConsolidationZones) + { + // + int count = state.CountBearishConsolidationZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCConsolidationZoneObject *iObj; + bool isCreated = CreateConsolidationZone( + state.bearishConsolidationZones[i], + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + // + int DrawOrderBlock( + XCOrderBlock *zone, + XCBaseObject *&objects[], + // + bool drawStartedBar = true, + bool drawActivatedBar = true, + bool drawBreakedBar = true, + bool drawWorkedBar = true, + // + int widthStartedBar = 1, + color clrStartedBar = clrYellow, + ENUM_LINE_STYLE styleStartedBar = STYLE_SOLID, + // + int widthActivatedBar = 1, + color clrActivatedBar = clrLime, + ENUM_LINE_STYLE styleActivatedBar = STYLE_SOLID, + // + int widthBreakedBar = 1, + color clrBreakedBar = clrRed, + ENUM_LINE_STYLE styleBreakedBar = STYLE_SOLID, + // + int widthWorkedBar = 1, + color clrWorkedBar = clrAqua, + ENUM_LINE_STYLE styleWorkedBar = STYLE_SOLID + // + ) + { + // + int result = 0; + + // + Clean(objects); + + // + if (zone == NULL || + !zone.IsValid()) + { + return result; + } + + // + ENUM_X_DIRECTION zoneDir = zone.GetDirection(); + + // + // Started Bar ... + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone + .IsStarted( + zoneDir, + startedBar, + isBodyOut // + ); + if (isStarted) + { + // + datetime iBarTo = startedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + startedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthStartedBar); + iBarObj.LowShadowWidth(widthStartedBar); + iBarObj.HighShadowWidth(widthStartedBar); + + // + iBarObj.BodyStyle(styleStartedBar); + iBarObj.LowShadowStyle(styleStartedBar); + iBarObj.HighShadowStyle(styleStartedBar); + + // + iBarObj.BodyColor(clrStartedBar); + iBarObj.LowShadowColor(clrStartedBar); + iBarObj.HighShadowColor(clrStartedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Activated Bar ... + XOHCL activatedBar; + bool isBodyIn = false; + bool isActivated = zone + .IsActivated( + zoneDir, + activatedBar, + isBodyIn, + false // Force Body Out Started ... + ); + if (isActivated) + { + // + datetime iBarTo = activatedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + activatedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthActivatedBar); + iBarObj.LowShadowWidth(widthActivatedBar); + iBarObj.HighShadowWidth(widthActivatedBar); + + // + iBarObj.BodyStyle(styleActivatedBar); + iBarObj.LowShadowStyle(styleActivatedBar); + iBarObj.HighShadowStyle(styleActivatedBar); + + // + iBarObj.BodyColor(clrActivatedBar); + iBarObj.LowShadowColor(clrActivatedBar); + iBarObj.HighShadowColor(clrActivatedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Breaked Bar ... + XOHCL breakedBar; + isBodyOut = false; + bool isBreaked = zone + .IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, // Ignore Start ... + false // Force Body Out Started ... + ); + if (isBreaked) + { + // + datetime iBarTo = breakedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + breakedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthBreakedBar); + iBarObj.LowShadowWidth(widthBreakedBar); + iBarObj.HighShadowWidth(widthBreakedBar); + + // + iBarObj.BodyStyle(styleBreakedBar); + iBarObj.LowShadowStyle(styleBreakedBar); + iBarObj.HighShadowStyle(styleBreakedBar); + + // + iBarObj.BodyColor(clrBreakedBar); + iBarObj.LowShadowColor(clrBreakedBar); + iBarObj.HighShadowColor(clrBreakedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Worked Bar ... + XOHCL workedBar; + isBodyOut = false; + bool isWorked = zone + .IsWorked( + zoneDir, + workedBar, + isBodyOut, + false, // Ignore Activation ... + false, // Force Body Out Started ... + false // Force Body In Activated ... + ); + if (isWorked) + { + // + datetime iBarTo = workedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + workedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthWorkedBar); + iBarObj.LowShadowWidth(widthWorkedBar); + iBarObj.HighShadowWidth(widthWorkedBar); + + // + iBarObj.BodyStyle(styleWorkedBar); + iBarObj.LowShadowStyle(styleWorkedBar); + iBarObj.HighShadowStyle(styleWorkedBar); + + // + iBarObj.BodyColor(clrWorkedBar); + iBarObj.LowShadowColor(clrWorkedBar); + iBarObj.HighShadowColor(clrWorkedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + XCBaseObject *iObj; + bool isCreated = CreateOrderBlock( + zone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + objects // + ); + } + + // + result = ArraySize(objects); + + // + return result; + } + + // + int DrawFairValueGap( + XCFVG *zone, + XCBaseObject *&objects[], + // + bool drawStartedBar = true, + bool drawActivatedBar = true, + bool drawBreakedBar = true, + bool drawWorkedBar = true, + // + int widthStartedBar = 1, + color clrStartedBar = clrYellow, + ENUM_LINE_STYLE styleStartedBar = STYLE_SOLID, + // + int widthActivatedBar = 1, + color clrActivatedBar = clrLime, + ENUM_LINE_STYLE styleActivatedBar = STYLE_SOLID, + // + int widthBreakedBar = 1, + color clrBreakedBar = clrRed, + ENUM_LINE_STYLE styleBreakedBar = STYLE_SOLID, + // + int widthWorkedBar = 1, + color clrWorkedBar = clrAqua, + ENUM_LINE_STYLE styleWorkedBar = STYLE_SOLID + // + ) + { + // + int result = 0; + + // + Clean(objects); + + // + if (zone == NULL || + !zone.IsValid()) + { + return result; + } + + // + ENUM_X_DIRECTION zoneDir = zone.GetDirection(); + + // + // Started Bar ... + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone + .IsStarted( + zoneDir, + startedBar, + isBodyOut // + ); + if (isStarted) + { + // + datetime iBarTo = startedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + startedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthStartedBar); + iBarObj.LowShadowWidth(widthStartedBar); + iBarObj.HighShadowWidth(widthStartedBar); + + // + iBarObj.BodyStyle(styleStartedBar); + iBarObj.LowShadowStyle(styleStartedBar); + iBarObj.HighShadowStyle(styleStartedBar); + + // + iBarObj.BodyColor(clrStartedBar); + iBarObj.LowShadowColor(clrStartedBar); + iBarObj.HighShadowColor(clrStartedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Activated Bar ... + XOHCL activatedBar; + bool isBodyIn = false; + bool isActivated = zone + .IsActivated( + zoneDir, + activatedBar, + isBodyIn, + false // Force Body Out Started ... + ); + if (isActivated) + { + // + datetime iBarTo = activatedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + activatedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthActivatedBar); + iBarObj.LowShadowWidth(widthActivatedBar); + iBarObj.HighShadowWidth(widthActivatedBar); + + // + iBarObj.BodyStyle(styleActivatedBar); + iBarObj.LowShadowStyle(styleActivatedBar); + iBarObj.HighShadowStyle(styleActivatedBar); + + // + iBarObj.BodyColor(clrActivatedBar); + iBarObj.LowShadowColor(clrActivatedBar); + iBarObj.HighShadowColor(clrActivatedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Breaked Bar ... + XOHCL breakedBar; + isBodyOut = false; + bool isBreaked = zone + .IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, // Ignore Start ... + false // Force Body Out Started ... + ); + if (isBreaked) + { + // + datetime iBarTo = breakedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + breakedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthBreakedBar); + iBarObj.LowShadowWidth(widthBreakedBar); + iBarObj.HighShadowWidth(widthBreakedBar); + + // + iBarObj.BodyStyle(styleBreakedBar); + iBarObj.LowShadowStyle(styleBreakedBar); + iBarObj.HighShadowStyle(styleBreakedBar); + + // + iBarObj.BodyColor(clrBreakedBar); + iBarObj.LowShadowColor(clrBreakedBar); + iBarObj.HighShadowColor(clrBreakedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + // Worked Bar ... + XOHCL workedBar; + isBodyOut = false; + bool isWorked = zone + .IsWorked( + zoneDir, + workedBar, + isBodyOut, + false, // Ignore Activation ... + false, // Force Body Out Started ... + false // Force Body In Activated ... + ); + if (isWorked) + { + // + datetime iBarTo = workedBar.NextAt(); + + // + XCOHCLObject *iBarObj; + bool isCreated = CreateBar( + workedBar, + iBarObj, + iBarTo // + ); + if (isCreated) + { + // + iBarObj.BodyWidth(widthWorkedBar); + iBarObj.LowShadowWidth(widthWorkedBar); + iBarObj.HighShadowWidth(widthWorkedBar); + + // + iBarObj.BodyStyle(styleWorkedBar); + iBarObj.LowShadowStyle(styleWorkedBar); + iBarObj.HighShadowStyle(styleWorkedBar); + + // + iBarObj.BodyColor(clrWorkedBar); + iBarObj.LowShadowColor(clrWorkedBar); + iBarObj.HighShadowColor(clrWorkedBar); + + // + Add( + (XCBaseObject *)iBarObj, + objects // + ); + } + } + + // + XCBaseObject *iObj; + bool isCreated = CreateFairValueGap( + zone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + objects // + ); + } + + // + result = ArraySize(objects); + + // + return result; + } + + // + int DrawOBFVG( + // + XOBFVG &item, + XCBaseObject *&objects[], + // + bool drawOrderBlock = true, + bool drawFairValueGaps = true, + bool drawAllFVGs = true, + // + bool drawOBStartedBar = true, + bool drawOBActivatedBar = true, + bool drawOBBreakedBar = true, + bool drawOBWorkedBar = true, + // + bool drawFVGStartedBar = true, + bool drawFVGActivatedBar = true, + bool drawFVGBreakedBar = true, + bool drawFVGWorkedBar = true, + // + // Order Block Specs ... + // + int widthOBStartedBar = 1, + color clrOBStartedBar = clrYellow, + ENUM_LINE_STYLE styleOBStartedBar = STYLE_SOLID, + // + int widthOBActivatedBar = 1, + color clrOBActivatedBar = clrLime, + ENUM_LINE_STYLE styleOBActivatedBar = STYLE_SOLID, + // + int widthOBBreakedBar = 1, + color clrOBBreakedBar = clrRed, + ENUM_LINE_STYLE styleOBBreakedBar = STYLE_SOLID, + // + int widthOBWorkedBar = 1, + color clrOBWorkedBar = clrAqua, + ENUM_LINE_STYLE styleOBWorkedBar = STYLE_SOLID, + // + // Fair Value Gap Specs ... + // + int widthFVGStartedBar = 1, + color clrFVGStartedBar = clrYellow, + ENUM_LINE_STYLE styleFVGStartedBar = STYLE_SOLID, + // + int widthFVGActivatedBar = 1, + color clrFVGActivatedBar = clrLime, + ENUM_LINE_STYLE styleFVGActivatedBar = STYLE_SOLID, + // + int widthFVGBreakedBar = 1, + color clrFVGBreakedBar = clrRed, + ENUM_LINE_STYLE styleFVGBreakedBar = STYLE_SOLID, + // + int widthFVGWorkedBar = 1, + color clrFVGWorkedBar = clrAqua, + ENUM_LINE_STYLE styleFVGWorkedBar = STYLE_SOLID + // + ) + { + // + int result = 0; + + // + Clean(objects); + + // + bool isValid = item.IsValid(); + if (!isValid) + { + return result; + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + XCBaseObject *tmpObjects[]; + + // + // Order Block ... + has = item.HasOB(); + if (has && + drawOrderBlock) + { + // + Clean(tmpObjects); + count = DrawOrderBlock( + item.ob, + tmpObjects, + drawOBStartedBar, + drawOBActivatedBar, + drawOBBreakedBar, + drawOBWorkedBar, + widthOBStartedBar, + clrOBStartedBar, + styleOBStartedBar, + widthOBActivatedBar, + clrOBActivatedBar, + styleOBActivatedBar, + widthOBBreakedBar, + clrOBBreakedBar, + styleOBBreakedBar, + widthOBWorkedBar, + clrOBWorkedBar, + styleOBWorkedBar // + ); + has = IsValidSize(count); + if (has) + { + // + Copy( + tmpObjects, + objects, + false // + ); + } + } + + // + // Fair Value Gap ... + if (!drawAllFVGs) + { + XCFVG *fvg; + has = item.GetMainFVG(fvg); + if (has && + drawFairValueGaps) + { + // + Clean(tmpObjects); + int fvgsCount = DrawFairValueGap( + fvg, + tmpObjects, + drawFVGStartedBar, + drawFVGActivatedBar, + drawFVGBreakedBar, + drawFVGWorkedBar, + widthFVGStartedBar, + clrFVGStartedBar, + styleFVGStartedBar, + widthFVGActivatedBar, + clrFVGActivatedBar, + styleFVGActivatedBar, + widthFVGBreakedBar, + clrFVGBreakedBar, + styleFVGBreakedBar, + widthFVGWorkedBar, + clrFVGWorkedBar, + styleFVGWorkedBar // + ); + has = IsValidSize(fvgsCount); + if (has) + { + // + Copy( + tmpObjects, + objects, + false // + ); + } + } + } + else + { + // + has = item.HasFVGs(); + if (has && + drawFairValueGaps) + { + // + count = item.CountFVGs(); + for (int i = 0; i < count; i++) + { + // + Clean(tmpObjects); + int fvgsCount = DrawFairValueGap( + item.fvgs[i], + tmpObjects, + drawFVGStartedBar, + drawFVGActivatedBar, + drawFVGBreakedBar, + drawFVGWorkedBar, + widthFVGStartedBar, + clrFVGStartedBar, + styleFVGStartedBar, + widthFVGActivatedBar, + clrFVGActivatedBar, + styleFVGActivatedBar, + widthFVGBreakedBar, + clrFVGBreakedBar, + styleFVGBreakedBar, + widthFVGWorkedBar, + clrFVGWorkedBar, + styleFVGWorkedBar // + ); + has = IsValidSize(fvgsCount); + if (has) + { + // + Copy( + tmpObjects, + objects, + false // + ); + } + } + } + } + + // + Clean(tmpObjects); + + // + result = ArraySize(objects); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + // Props ... + + // + string mPrefix; // Prefix of Created Objects ... + long mChartIdentification; // Chart Id ... + int mSubWindowIdentification; // Sub Window ... + + // + // XOHCL ... + int mBarWidth; // Bar Width ... + color mBarBullishColor; // Bar Bullish Color ... + color mBarBearishColor; // Bar Bearish Color ... + bool mBarFillHighShadow; // Fill Bar High Shadow ... + ENUM_LINE_STYLE mBarHighShadowStyle; // Bar High Shadow Style ... + bool mBarFillBody; // Fill Bar Body ... + ENUM_LINE_STYLE mBarBodyStyle; // Bar Body Style ... + bool mBarFillLowShadow; // Fill Bar Low Show ... + ENUM_LINE_STYLE mBarLowShadowStyle; // Bar Low Shadow Style ... + + // + // Swing Low ... + int mSwingLowWidth; // Swing Low Width ... + int mSwingLowArrow; // Swing Low Arrow Code ... + color mSwingLowColor; // Swing Low Color ... + + // + // Swing High ... + int mSwingHighWidth; // Swing High Width ... + int mSwingHighArrow; // Swing High Arrow Code ... + color mSwingHighColor; // Swing High Color ... + + // + // Bullish Momentum Bar ... + int mBullishMomentumBarWidth; // Bullish Momentum Bar Width ... + int mBullishMomentumBarArrow; // Bullish Momentum Bar Arrow Code ... + color mBullishMomentumBarColor; // Bullish Momentum Bar Color ... + + // + // Bearish Momentum Bar ... + int mBearishMomentumBarWidth; // Bearish Momentum Bar Width ... + int mBearishMomentumBarArrow; // Bearish Momentum Bar Arrow Code ... + color mBearishMomentumBarColor; // Bearish Momentum Bar Color ... + + // + // Bullish Rejection Bar ... + int mBullishRejectionBarWidth; // Bullish Rejection Bar High Width ... + int mBullishRejectionBarArrow; // Bullish Rejection Bar High Arrow Code ... + color mBullishRejectionBarColor; // Bullish Rejection Bar High Color ... + + // + // Bearish Rejection Bar ... + int mBearishRejectionBarWidth; // Bearish Rejection Bar Width ... + int mBearishRejectionBarArrow; // Bearish Rejection Bar Arrow Code ... + color mBearishRejectionBarColor; // Bearish Rejection Bar Color ... + + // + // Supply Zone ... + bool mSupplyZoneFill; // Fill Supply Zone ... + int mSupplyZoneWidth; // Supply Zone Width ... + color mSupplyZoneColor; // Supply Zone Color ... + ENUM_LINE_STYLE mSupplyZoneStyle; // Supply Zone Style ... + + // + // Demand Zone ... + bool mDemandZoneFill; // Fill Demand Zone ... + int mDemandZoneWidth; // Demand Zone Width ... + color mDemandZoneColor; // Demand Zone Color ... + ENUM_LINE_STYLE mDemandZoneStyle; // Demand Zone Style ... + + // + // Resistance Zone ... + bool mResistanceZoneFill; // Fill Resistance Zone ... + int mResistanceZoneWidth; // Resistance Zone Width ... + color mResistanceZoneColor; // Resistance Zone Color ... + ENUM_LINE_STYLE mResistanceZoneStyle; // Resistance Zone Style ... + + // + // Support Zone ... + bool mSupportZoneFill; // Fill Support Zone ... + int mSupportZoneWidth; // Support Zone Width ... + color mSupportZoneColor; // Support Zone Color ... + ENUM_LINE_STYLE mSupportZoneStyle; // Support Zone Style ... + + // + // Bullish Order Block ... + bool mBullishOrderBlockFill; // Fill Bullish Order Block ... + int mBullishOrderBlockWidth; // Bullish Order Block Width ... + color mBullishOrderBlockColor; // Bullish Order Block Color ... + ENUM_LINE_STYLE mBullishOrderBlockStyle; // Bullish Order Block Style ... + + // + // Bearish Order Block ... + bool mBearishOrderBlockFill; // Fill Bearish Order Block ... + int mBearishOrderBlockWidth; // Bearish Order Block Width ... + color mBearishOrderBlockColor; // Bearish Order Block Color ... + ENUM_LINE_STYLE mBearishOrderBlockStyle; // Bearish Order Block Style ... + + // + // Bullish FVG ... + bool mBullishFVGFill; // Fill Bullish FVG ... + int mBullishFVGWidth; // Bullish FVG Width ... + color mBullishFVGColor; // Bullish FVG Color ... + ENUM_LINE_STYLE mBullishFVGStyle; // Bullish FVG Style ... + + // + // Bearish FVG ... + bool mBearishFVGFill; // Fill Bearish FVG ... + int mBearishFVGWidth; // Bearish FVG Width ... + color mBearishFVGColor; // Bearish FVG Color ... + ENUM_LINE_STYLE mBearishFVGStyle; // Bearish FVG Style ... + + // + // Ticks Zone ... + XTickZoneLevelSpecs mTicksZoneSpecs[]; // Zone Draw Specifications ... + + // +}; \ No newline at end of file diff --git a/BKPS/14031218/Classes/x-saherelm.x-trade.class.mq5 b/BKPS/14031218/Classes/x-saherelm.x-trade.class.mq5 new file mode 100644 index 0000000..7bdd19f --- /dev/null +++ b/BKPS/14031218/Classes/x-saherelm.x-trade.class.mq5 @@ -0,0 +1,3934 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-account.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +// Overrides ... + +// +// XCTrade Base Class ... +class XCTradeBase : public CTrade +{ + public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// Implementation ... + +// +// a Class For Manage Trades and Handle Trading Actions ... +class XCTrade : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAccount *mAccount; // Account Info Provider + + // + // Constructors ... + void XCTrade( + int slippage, // Specify Slippage + ulong magicNumber, // Specify Magic Number + double maxAllowedSpread = 0, // Max Allowed Spred for Opening Trades + int maxAllowedPositions = 0, // Max Allowed Positions + double maxAllowedDrawdownFactor = 0 // Max Allowed Drawdown Factor + ) + { + // + // Setting Props ... + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mMaxAllowedSpread = maxAllowedSpread; + mMaxAllowedPositions = maxAllowedPositions; + mMaxAllowedDrawdownFactor = maxAllowedDrawdownFactor; + + // + mAccount = new XCAccount(); + + // + // Instance Base Trader Class ... + mTrader = new XCTradeBase(); + + // + // Configuring Base Trader Class ... + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // OnTrade Context ... + + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + ~XCTrade() + { + // + // Remove Pointer ... + delete mTrader; + delete mAccount; + + // + ZeroMemory(mTrader); + ZeroMemory(mAccount); + + // + Clean(mOnModifyEventHandlers); + Clean(mStopLossEventHandlers); + Clean(mTakeProfitEventHandlers); + Clean(mOnForceCloseEventHandlers); + Clean(mDealsChangedEventHandlers); + Clean(mOrdersChangedEventHandlers); + Clean(mOnPartialCloseEventHandlers); + Clean(mPositionsChangedEventHandlers); + Clean(mTradeStateChangedEventHandlers); + } + + // + // Props ... + + // + // Retrieve Slippage ... + int GetSlippage() + { + return mSlippage; + } + + // + // Retrieve Magic Number ... + ulong GetMagicNumber() + { + return mMagicNumber; + } + + // + double GetMaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + // + int GetMaxAllowedPositions() + { + return mMaxAllowedPositions; + } + + // + void SetMaxAllowedPositions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedPositions = value; + } + + // + double GetMaxAllowedDrawdownFactor() + { + return mMaxAllowedDrawdownFactor; + } + + // + // Add Event Listeners ... + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + // Functions ... + + // + // Handlers ... + + // + // Process On Trade Requirement ... + // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + result.Clean(); + + // + if (mScanStarted) + { + // + ProcessOnTradeContext(result); + } + else + { + // + // Init Trade Context ... + InitOnTradeContext(); + + // + return; + } + + // + // Here we Can Check the Start ... + bool isValid = + // + result.IsValid() && + // + !result.hasNewDeal && + !result.hasNewOrder && + !result.hasNewPosition && + !result.hasNewHistoryOrder + // + ; + if (!isValid) + { + return; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(result); + + // + // Deals ... + if (result.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(result.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + int dealsCount = GetDeals(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // Orders ... + if (result.hasNewOrder || result.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); + } + + // + // Positions ... + if (result.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(result.newPositions); + } + } + + // + // This Must be Called Every time OnTrade Event Happening ... + // this Used for Implementing Custom Senarios ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Trade Actions ... + + // + // Main ... + + // + // Policies ... + + // + // Check Acocunt Balance is Allow new Trades or not ... + bool CheckEquityForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedDrawdownFactor <= 0) + { + // + result = true; + return result; + } + + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); + + // + double maxAllowedBalanceDrawDown = GetMaxAllowedEquity(); + + // + result = equity > balance || + (equity <= balance && + selectedBalance <= maxAllowedBalanceDrawDown); + + // + return result; + } + + // + // Check Max Allowed Positions Policy for Trade ... + bool CheckPositionsForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedPositions <= 0) + { + // + result = true; + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (positionsCount <= 0) + { + // + result = true; + return result; + } + + // + result = positionsCount < mMaxAllowedPositions; + + // + return result; + } + + // + // Check Spread is Ok for Executing Specific Signal ... + bool CheckSpreadForSignalExecution(XSignal &mSignal) + { + // + bool result = false; + + // + bool isSpreadCheckEnable = mMaxAllowedSpread > 0; + if (!isSpreadCheckEnable) + { + result = true; + } + else + { + // + // Retrieve Signal Spread ... + double spread = GetSpread(mSignal.symbol); + result = spread <= mMaxAllowedSpread; + } + + // + return result; + } + + // + // Check Account Policy ... + bool CheckAccountPolicy( + XSignal &mSignal, // For Executing Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state // State Holder + ) + { + // + bool result = false; + + // + // Check Positions For Trade ... + result = CheckPositionsForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + + // + // Check Equity For Trade ... + result = CheckEquityForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + + // + // Check Spread for Trade ... + result = CheckSpreadForSignalExecution(mSignal); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_SPREAD; + return result; + } + + // + return result; + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &mSignal, // Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + bool result = false; + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + double currentEntry = GetEntry( + mSignal.symbol, + mSignal.type + // + ); + bool isLong = IsLong(mSignal.type); + + // + if (!mSignal.IsValid()) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + // Prepare Signal Comment ... + string mSComment = mSignal.GenerateComment(); + if (!Contains(mSComment, mSignal.comment)) + { + mSignal.comment += mSComment; + } + + // + // Handle Market Execution ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + // + // Do Apply Policies here ... + bool hasPolicy = !checkPolicies + ? true + : CheckAccountPolicy(mSignal, state); + if (!hasPolicy) + { + result = false; + } + else + { + // + if (isLong) + { + // + result = Buy( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + else + { + // + result = Sell( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + } + } + // + // Handle Stop Execution ... + else if (mSignal.mode == X_ORDER_MODE_STOP) + { + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry > currentEntry + : mSignal.entry < currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + // + // Handle Limit Execution ... + else if (mSignal.mode == X_ORDER_MODE_LIMIT) + { + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry < currentEntry + : mSignal.entry > currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + + // + // Handle Ticket ... + if (result) + { + // + state = X_SIGNAL_EXECUTION_SUCCEED; + + // + ulong ticket; + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + ticket = GetLastOpenPositionTicket(); + } + else + { + ticket = GetLastPlacedOrderTicket(); + } + + // + mSignal.positionId = ticket; + + // + // Handle Store XPositionInfo ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + // + // TODO: Implement this ... + } + + // + // Handle Executing Support Signals ... + int supportsCount = ArraySize(mSignal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = mSignal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportTag(ticket); + iSupport.comment = iComment; + + // + bool isExecuted = ExecuteSignal( + iSupport, + state, + lifetime, + expiration + // + ); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; + } + + // + // Execute a Collection Of Signals ... + int ExecuteSignals( + XSignal &signals[], // Collection of Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration, + checkPolicies + // + ); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + int ExecuteSpecifiedSignals( + XSignal &signals[], // Collection of Signal for Execution + XSignal ¬Executeds[], // Not Executed Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + Clean(notExecuteds); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration + // + ); + + // + if (isExecuted) + { + result++; + } + else + { + // + AddRef( + signals[i], + notExecuteds // + ); + } + } + + // + return result; + } + + // + // Regular Trade Actions ... + + // + // Buy ... + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Sell ... + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Check a Position is Exists Open or not ... + bool IsOpen( + ulong ticket // Specified Position Ticket + ) + { + // + bool result = false; + + // + result = mPositionInfo + .SelectByTicket(ticket); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = NULL // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + XPosition position; + result = + GetPosition( + ticket, + position // + ) && + (tp >= 0 || sl >= 0); + if (!result) + { + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (!IsValid(comment) == 0) + { + // + // if there isn't provided Comment + // Use Position Comment for default ... + comment = "Modify " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment + // + ); + if (result) + { + // + NotifyModifyEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Check Position Open ... + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Position Comment if it's Not Provided ... + if (!IsValid(comment)) + { + comment = "Close " + GetPositionComment(ticket); + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyForceCloseEvent( + ticket, + position, + comment // + ); + } + + // + return result; + } + + // + // Close Specified Positions ... + int Close( + string comment = NULL, // Close Position By Specific Comment + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + int result = 0; + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close a Collection of Positions ... + int Close( + XPosition &positions[], // Collection of Positions + string comment // Close Comment + ) + { + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Partial Close Comment ... + if (!IsValid(comment)) + { + // + comment += "PClose " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyPartialCloseEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader + .OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + int CancelOrders( + XOrder &orders[] // Specified Orders ... + ) + { + // + int result = 0; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader + .OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result++; + } + } + + // + return result; + } + + // + // Extractors ... + + // + // Positions ... + + // + // Calculate Positions Profit ... + double Profit( + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + double result = 0; + + // + // Retrieve Positions ... + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic + // + ); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + result += positions[i].profit; + } + + // + return result; + } + + // + // Retrieve Specific Position by Index ... + bool GetPosition( + int index, // Specified Index + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByIndex(index); + + // + return isInited; + } + + // + // Retrieve Specific Position by Ticket ... + bool GetPosition( + ulong ticket, // Specified Ticket + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByTicket(ticket); + + // + return isInited; + } + + // + double GetPositionCommission( + ulong ticket // Specified Ticket + ) + { + // + double result = 0; + + // + XPosition position; + bool hasPosition = GetPosition( + ticket, + position // + ); + if (!hasPosition) + { + return result; + } + + // + XDeal deals[]; + int dealsCount = GetDeals( + deals, + position.symbol, + position.provider, + position.period, + NULL, + DEAL_ENTRY_IN // + ); + if (IsValidSize(dealsCount)) + { + // + for (int i = 0; i < dealsCount; i++) + { + // + XDeal iDeal = deals[i]; + if (iDeal.positionId == ticket) + { + // + result = iDeal.commission; + break; + } + } + } + + // + return result; + } + + // + // Retrieve Positions ... + int GetPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = PositionsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XPosition iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + void GetPositions( + XPosition &longs[], // Hold's Longs Result + XPosition &shorts[], // Hold's Shorts Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + // Retrieve Long Positions ... + GetPositions( + longs, + symbol, + provider, + period, + X_POSITION_TYPE_LONG, + filterByMagic, + forceClean // + ); + + // + // Retrieve Short Positions ... + GetPositions( + shorts, + symbol, + provider, + period, + X_POSITION_TYPE_SHORT, + filterByMagic, + forceClean // + ); + } + + // + // Select In Profit Positions ... + int GetInProfitPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit <= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Drawdown Positions ... + int GetInDrawdownPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit >= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Orders ... + + // + // Retrieve Specific Order by Index ... + bool GetOrder( + int index, // Specified Index + XOrder &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Positions Orders ... + int GetOrders( + ulong ticket, // Positions Ticket + XOrder &result[], // Hold's Result + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + // Select History by Specified Ticket ... + bool isHistorySelected = HistorySelectByPosition(ticket); + if (!isHistorySelected) + { + return mResult; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder; + bool isLoaded = iOrder.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + bool isTicketFilterPassed = + // + iOrder.ticket = ticket + // + ; + if (!isTicketFilterPassed) + { + continue; + } + + // + AddRef( + iOrder, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve All Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve Historical Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Deals ... + + // + // Retrieve Specific Deal by Index ... + bool GetDeal( + int index, // Specified Index + XDeal &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + bool GetLastDeal( + XDeal &result // Hold's Result + ) + { + // + bool mResult = false; + + // + mResult = HistorySelect(0, TimeCurrent()); + if (!mResult) + { + return mResult; + } + + // + int lastDealIndex = HistoryDealsTotal() - 1; + + // + mResult = GetDeal( + lastDealIndex, + result // + ); + + // + return mResult; + } + + // + // Retrieve Specified Deal's History ... + int GetDealsHistory( + XDeal &deal, // Specified Deal + XOrder &history[], // Deals History + bool forceClean = true // Clean Result Array + ) + { + // + int result = 0; + + // + if (!deal.IsValid()) + { + return result; + } + + // + result = GetOrders( + deal.positionId, + history, + forceClean); + + // + return result; + } + + // + // Retrieve All Deals ... + int GetDeals( + XDeal &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_DEAL_TYPE type = NULL, // Deal Type + ENUM_DEAL_ENTRY entry = NULL, // Deal Entry + ENUM_DEAL_REASON reason = NULL, // Deal Reason + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = HistoryDealsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XDeal iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + entry, + reason, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Support Functions ... + + // + // Check a Position has Support or not ... + bool HasSupport( + ulong ticket, + bool forceOpen = true // + ) + { + // + bool result = false; + + // + result = ticket > 0; + if (!result) + { + return result; + } + + // + if (forceOpen) + { + // + result = IsOpen(ticket); + if (!result) + { + return result; + } + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + result = IsValidSize(positionsCount); + if (!result) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + result = IsValidSize(supportsCount); + if (!result) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + result = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (result) + { + break; + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XPosition &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XOrder &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XOrder orders[]; + int ordersCount = GetOrders( + orders, + NULL, // All Symbols ... + NULL, // All Providers ... + NULL, // All Periods ... + X_POSITION_TYPE_ALL, // All Types ... + ORDER_STATE_PLACED, // Untriggere Orders ... + true // + ); + if (!IsValidSize(ordersCount)) + { + return result; + } + + // + // Extract Support Positions ... + XOrder supports[]; + int supportsCount = ExtractSupports( + orders, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XOrder iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Tools ... + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // Prepare Dynamic Volume ... + double GetDynamicVolume( + string _symbol, + double _balanceFactor, + double _volumeStep // + ) + { + // + double result = 0; + + // + // Validate Inputs ... + if (!IsValid(_symbol) || + _volumeStep <= 0 || + _balanceFactor <= 0) + { + return result; + } + + // + // Retrieve Account Balance ... + double balance = mAccount.GetBalance(); + + // + double bStep = balance / _balanceFactor; + bStep = MathFloor(bStep); + if (bStep == 0) + { + bStep = 1; + } + + // + result = bStep * _volumeStep; + + // + result = NormalizeVolume( + result, + _symbol // + ); + + // + return result; + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Event Listener Notifiers ... + + // + // State ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // Deals ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Orders ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Positions ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // StopLoss ... + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + // Take Profit ... + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyModifyEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnModifyEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnModifyEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + void NotifyForceCloseEvent( + ulong ticket, + XPosition &position, + string comment // + ) + { + // + int count = ArraySize(mOnForceCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnForceClose iHandler = mOnForceCloseEventHandlers[i]; + iHandler( + ticket, + position, + comment // + ); + } + } + + // + void NotifyPartialCloseEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnPartialCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnPartialCloseEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + // Tools ... + + // + // Retrieve Specified Position Comment ... + string GetPositionComment(ulong ticket) + { + // + string result = NULL; + + // + if (!IsOpen(ticket)) + { + return result; + } + + // + XPosition position; + bool isLoaded = position.ByTicket(ticket); + if (!isLoaded) + { + return result; + } + + // + result = position.comment; + + // + return result; + } + + // + ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder orders[]; + int ordersCount = GetDealsHistory( + deal, + orders); + if (!ordersCount) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (IsValid(iOrder.comment)) + { + // + ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); + if (IsValid(iPeriod)) + { + result = iPeriod; + break; + } + } + } + + // + return result; + } + + // + double GetMaxAllowedEquity() + { + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double balanceForFactor = MathAbs(equity - balance); + if (balanceForFactor <= 0) + { + balanceForFactor = balance; + } + else + { + balanceForFactor = equity; + } + + // + double result = balanceForFactor * mMaxAllowedDrawdownFactor; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mSlippage; // Slippage ... + ulong mMagicNumber; // Magic Number (Unique Identifier) ... + + // + double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades + int mMaxAllowedPositions; // Max Allowed Same Positions + double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor + + // + XCTradeBase *mTrader; // Base CTrade Manipulated Instance ... + + // + CDealInfo mDealInfo; // Deals Info ... + COrderInfo mOrderInfo; // Order Info ... + CPositionInfo mPositionInfo; // Positions Info + CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... + + // + // Position Info Collector ... + + // + // Tools ... + + // + // OnTrade Event Handlers Section ... + + // + // Props ... + + // + int mDaysForRead; // Reading Dates for Trade History Checker ... + datetime mEndDate; // End Date for Trade history Checking ... + datetime mStartDate; // Start Date for Trade history Checking ... ... + int mOrdersCount; // Number of Active orders ... + int mPositionsCount; // Number of Open positions ... + int mDealsCount; // Number of Deals in the Trade History Checking ... + int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... + bool mScanStarted; // a Flag of counter relevance ... + + // + // Event Listeners ... + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + TOnModify mOnModifyEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/1.ind.ai.mq5 b/BKPS/14031218/Documents/BKP/1.ind.ai.mq5 new file mode 100644 index 0000000..34d2e5f --- /dev/null +++ b/BKPS/14031218/Documents/BKP/1.ind.ai.mq5 @@ -0,0 +1,196 @@ +//+------------------------------------------------------------------+ +//| HH_LH_LL_HL.mq5 | +//| Indicator for detecting HH, LH, LL, HL | +//| Created by [Your Name] | +//+------------------------------------------------------------------+ + +#property copyright "Your Name" +#property link "yourwebsite.com" +#property version "1.00" +#property indicator_chart_window +#property indicator_buffers 4 +#property indicator_plots 4 + +//--- Input parameters +input int LookbackPeriod = 20; // Number of bars to look back for pattern detection + +//--- Buffer declarations +double HH_Buffer[]; // Buffer for Higher Highs +double HL_Buffer[]; // Buffer for Higher Lows +double LH_Buffer[]; // Buffer for Lower Highs +double LL_Buffer[]; // Buffer for Lower Lows + +//--- Plot settings +#property indicator_label1 "Higher Highs" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +#property indicator_label2 "Higher Lows" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrBlue +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +#property indicator_label3 "Lower Highs" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrRed +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +#property indicator_label4 "Lower Lows" +#property indicator_type4 DRAW_ARROW +#property indicator_color4 clrYellow +#property indicator_style4 STYLE_SOLID +#property indicator_width4 1 + +//+------------------------------------------------------------------+ +//| Initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Set buffer properties + SetIndexBuffer(0, HH_Buffer); + SetIndexBuffer(1, HL_Buffer); + SetIndexBuffer(2, LH_Buffer); + SetIndexBuffer(3, LL_Buffer); + + // Clear buffers at each bar + ArrayInitialize(HH_Buffer, 0.0); + ArrayInitialize(HL_Buffer, 0.0); + ArrayInitialize(LH_Buffer, 0.0); + ArrayInitialize(LL_Buffer, 0.0); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // Cleanup if necessary +} + +//+------------------------------------------------------------------+ +//| Calculate function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) +{ + // Start from the last calculated bar + int start_bar = MathMax(prev_calculated - 1, 0); + + // Loop through bars + for (int i = start_bar; i < rates_total; i++) + { + // Get current high and low + double current_high = high[i]; + double current_low = low[i]; + + // Check for Higher High (HH) + if (IsHigherHigh(i, high, LookbackPeriod)) + { + HH_Buffer[i] = current_high; + HL_Buffer[i] = 0.0; // Reset other buffers + LH_Buffer[i] = 0.0; + LL_Buffer[i] = 0.0; + } + // Check for Higher Low (HL) + else if (IsHigherLow(i, low, LookbackPeriod)) + { + HL_Buffer[i] = current_low; + HH_Buffer[i] = 0.0; + LH_Buffer[i] = 0.0; + LL_Buffer[i] = 0.0; + } + // Check for Lower High (LH) + else if (IsLowerHigh(i, high, LookbackPeriod)) + { + LH_Buffer[i] = current_high; + HH_Buffer[i] = 0.0; + HL_Buffer[i] = 0.0; + LL_Buffer[i] = 0.0; + } + // Check for Lower Low (LL) + else if (IsLowerLow(i, low, LookbackPeriod)) + { + LL_Buffer[i] = current_low; + HH_Buffer[i] = 0.0; + HL_Buffer[i] = 0.0; + LH_Buffer[i] = 0.0; + } + else + { + // Reset all buffers if no pattern is detected + HH_Buffer[i] = 0.0; + HL_Buffer[i] = 0.0; + LH_Buffer[i] = 0.0; + LL_Buffer[i] = 0.0; + } + } + + // + return rates_total; +} + +//+------------------------------------------------------------------+ +//| Function to detect Higher High | +//+------------------------------------------------------------------+ +bool IsHigherHigh(int index, const double &high[], int lookback) +{ + for (int i = 1; i <= lookback; i++) + { + if (index - i < 0) continue; // Ensure we don't go out of bounds + if (high[index] <= high[index - i]) return false; + } + return true; +} + +//+------------------------------------------------------------------+ +//| Function to detect Higher Low | +//+------------------------------------------------------------------+ +bool IsHigherLow(int index, const double &low[], int lookback) +{ + for (int i = 1; i <= lookback; i++) + { + if (index - i < 0) continue; // Ensure we don't go out of bounds + if (low[index] <= low[index - i]) return false; + } + return true; +} + +//+------------------------------------------------------------------+ +//| Function to detect Lower High | +//+------------------------------------------------------------------+ +bool IsLowerHigh(int index, const double &high[], int lookback) +{ + for (int i = 1; i <= lookback; i++) + { + if (index - i < 0) continue; // Ensure we don't go out of bounds + if (high[index] >= high[index - i]) return false; + } + return true; +} + +//+------------------------------------------------------------------+ +//| Function to detect Lower Low | +//+------------------------------------------------------------------+ +bool IsLowerLow(int index, const double &low[], int lookback) +{ + for (int i = 1; i <= lookback; i++) + { + if (index - i < 0) continue; // Ensure we don't go out of bounds + if (low[index] >= low[index - i]) return false; + } + return true; +} \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/1.mq5 b/BKPS/14031218/Documents/BKP/1.mq5 new file mode 100644 index 0000000..fd7da80 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/1.mq5 @@ -0,0 +1,10874 @@ + +// +// Fix Signal TP Based On Working Zone ... +// double maxAllowedTP = +// hasLong +// ? mXWZConditions.workingZone.upper +// : mXWZConditions.workingZone.lower; +// bool canApplyMaxAlowedTP = (hasLong && +// signal.tp > maxAllowedTP) || +// (!hasLong && signal.tp < maxAllowedTP); +// if (canApplyMaxAlowedTP) +// { +// signal.tp = maxAllowedTP; +// } + +// +// Configuring Global Protector ... +// signal.trailSL = true; +// signal.trailSLStartOnReachTPLevel = 3; +// signal.fullTPLevel = signal.GetRiskRewardRatio(); + +// // +// mXSupDemOBSSignalDetector.RemoveDraws(); +// mXSupDemOBSSignalDetector.DrawConditions( +// mXSupDemOBSConditions, +// mVisionCycleHelper.mPOIDrawer // +// ); + +// // +// mXSupDemOBSSignalDetector.RemoveWorkingZoneDraws(); +// mXSupDemOBSSignalDetector.DrawWorkingZone( +// mXSupDemOBSConditions, +// mVisionCycleHelper.mPOIDrawer // +// ); + +// +// bool canReplaceTarget = +// signal.target > 0 && +// (hasLong +// ? signal.target > signal.tp +// : signal.target < signal.tp); +// if (canReplaceTarget) +// { +// // +// signal.tp = conditions.target; +// signal.target = tp; +// } + +// +// consolidationState.UpdateTo(cTime); +// XPOIState filtered; +// consolidationState.Filter( +// filtered, +// NULL, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); +// XCBaseObject *objects[]; +// int objectsCount = drawer.DrawState( +// filtered, +// objects // +// ); +// if (IsValidSize(objectsCount)) +// { +// // +// Print(""); +// } + +// // +// XOBFVG activeObfvgs[]; +// int activeObfvgsCount = ExtractOBFVGs( +// activeObfvgs, +// consolidationState, +// analyseState // +// ); +// bool hasActiveOBFVGs = IsValidSize(activeObfvgsCount); +// if (hasActiveOBFVGs) +// { +// // +// SpecifiedUpdateTo(activeObfvgs); +// for (int i = 0; i < activeObfvgsCount; i++) +// { +// // +// XCBaseObject *objects[]; +// int objectsCount = drawer.DrawOBFVG( +// activeObfvgs[i], +// objects // +// ); +// } +// } + +// // +// // Swings ... +// bool lookupSwings = ArraySize(mSwingLows) < mMaxRequiredPOIs || +// ArraySize(mSwingHighs) < mMaxRequiredPOIs; +// lookupSwings = +// ignoreMaxAllowed +// ? true +// : lookupSwings; +// if (has && +// lookupSwings) +// { +// } + +// // +// // Momentum Bar ... +// bool lookupMomentums = ArraySize(mBullishMomentumBars) < mMaxRequiredPOIs || +// ArraySize(mBearishMomentumBars) < mMaxRequiredPOIs; +// lookupMomentums = +// ignoreMaxAllowed +// ? true +// : lookupMomentums; +// if (has && +// lookupMomentums) +// { +// } + +// // +// // Rejection Bar ... +// bool lookupRejections = ArraySize(mBullishRejectionBars) < mMaxRequiredPOIs || +// ArraySize(mBearishRejectionBars) < mMaxRequiredPOIs; +// lookupRejections = +// ignoreMaxAllowed +// ? true +// : lookupRejections; +// if (has && +// lookupRejections) +// { +// } + +// // +// // Support ... +// bool lookupSupports = ArraySize(mSupportZones) < mMaxRequiredPOIs; +// lookupSupports = +// ignoreMaxAllowed +// ? true +// : lookupSupports; +// if (has && +// lookupSupports) +// { +// } + +// // +// // Demand ... +// bool lookupDemands = ArraySize(mDemandZones) < mMaxRequiredPOIs; +// lookupDemands = +// ignoreMaxAllowed +// ? true +// : lookupDemands; +// if (has && +// lookupDemands) +// { +// } + +// // +// // Resistance ... +// bool lookupResistance = ArraySize(mResistanceZones) < mMaxRequiredPOIs; +// lookupResistance = +// ignoreMaxAllowed +// ? true +// : lookupResistance; +// if (has && +// lookupResistance) +// { +// } + +// // +// // Supply ... +// bool lookupSupplies = ArraySize(mSupplyZones) < mMaxRequiredPOIs; +// lookupSupplies = +// ignoreMaxAllowed +// ? true +// : lookupSupplies; +// if (has && +// lookupSupplies) +// { +// } + +// // +// // OrderBlock ... +// bool lookupOrderBlocks = ArraySize(mBullishOrderBlocks) < mMaxRequiredPOIs || +// ArraySize(mBearishOrderBlocks) < mMaxRequiredPOIs; +// lookupOrderBlocks = +// ignoreMaxAllowed +// ? true +// : lookupOrderBlocks; +// if (has && +// lookupOrderBlocks) +// { +// } + +// // +// // FairValueGap ... +// bool lookupFairValeGaps = ArraySize(mBullishFairValueGaps) < mMaxRequiredPOIs || +// ArraySize(mBearishFairValueGaps) < mMaxRequiredPOIs; +// lookupFairValeGaps = +// ignoreMaxAllowed +// ? true +// : lookupFairValeGaps; +// if (has && +// (lookupFairValeGaps)) +// { +// } + +// +XCBaseObject *stateObjects[]; +int stateObjectsCount = drawer.DrawState( + decisionState, + stateObjects, + false, // + true, // ignoreSwingHighs + true, // ignoreSwingLows + true, // ignoreSupportZones + true, // ignoreResistanceZones + true, // ignoreSupplyZones + true, // ignoreDemandZones + true, // ignoreBullishOrderBlocks + true, // ignoreBearishOrderBlocks + true, // ignoreBullishFairValueGaps + true, // ignoreBearishFairValueGaps + true, // ignoreBullishRejectionBars + true, // ignoreBearishRejectionBars + true, // ignoreBullishMomentumBars + true, // ignoreBearishMomentumBars + false, // ignoreBullishConsolidationZones + false // ignoreBearishConsolidationZones +); + +// +// Draw ... +if (hasSelectedConsolidationZone) +{ + // + XCConsolidationZoneObject *iObj; + selectedConsolidationZone.to = cTime; + bool isCreated = drawer.CreateConsolidationZone( + selectedConsolidationZone, + iObj // + ); +} + +///////////////////////////////////////////////////////////////////////////////////// + +// // +// // Based On Waiting Zones ... +// has = isBarInited && +// hasWorkingZone; +// if (has) +// { +// // +// XOBFVG tmpZones[]; +// Copy( +// workingZone.waitingZones, +// tmpZones // +// ); + +// // +// while (HasChild(tmpZones)) +// { +// // +// XOBFVG iOBFVG; + +// // +// idx = GetYoungest(tmpZones); +// if (!IsValidIndex(idx)) +// { +// // +// iOBFVG.Clean(); +// break; +// } + +// // +// iOBFVG = tmpZones[idx]; +// ArrayRemove( +// tmpZones, +// idx, +// 1 // +// ); + +// // +// double iTarget = +// isSelectedZonDirBullish +// ? iOBFVG.ob.Lower() +// : iOBFVG.ob.Upper(); + +// // +// has = +// isSelectedZonDirBullish +// ? cBar.high < iTarget +// : cBar.low > iTarget; + +// // +// if (has) +// { +// // +// Add( +// iTarget, +// targets // +// ); +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// Clean(tmpZones); +// } + +// // +// // Based On Breaked Zones ... +// has = isBarInited && +// hasBreakedZones; +// if (has) +// { +// // +// XOBFVG tmpZones[]; +// Copy( +// workingZone.breakedZones, +// tmpZones // +// ); + +// // +// while (HasChild(tmpZones)) +// { +// // +// XOBFVG iOBFVG; + +// // +// idx = GetYoungest(tmpZones); +// if (!IsValidIndex(idx)) +// { +// // +// iOBFVG.Clean(); +// break; +// } + +// // +// iOBFVG = tmpZones[idx]; +// ArrayRemove( +// tmpZones, +// idx, +// 1 // +// ); + +// // +// double iTarget = +// isSelectedZonDirBullish +// ? iOBFVG.ob.Lower() +// : iOBFVG.ob.Upper(); + +// // +// has = +// isSelectedZonDirBullish +// ? cBar.high < iTarget +// : cBar.low > iTarget; + +// // +// if (has) +// { +// // +// Add( +// iTarget, +// targets // +// ); +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// Clean(tmpZones); +// } + +// // +// // Based On Priority ... +// if (hasPriority) +// { +// // +// switch (priority) +// { +// // +// case X121SMC_XWZ_PRIORITY_WEAK: +// // +// if (isSelectedZonDirBullish) +// { +// // +// // Weak ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); +// } +// else +// { +// // +// // Weak ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); +// } +// break; + +// // +// case X121SMC_XWZ_PRIORITY_LOW: +// // +// if (isSelectedZonDirBullish) +// { +// // +// // Weak ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter1, +// targets // +// ); +// } +// else +// { +// // +// // Weak ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter3, +// targets // +// ); +// } +// break; + +// // +// case X121SMC_XWZ_PRIORITY_REGULAR: +// // +// if (isSelectedZonDirBullish) +// { +// // +// // Weak ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter1, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); +// } +// else +// { +// // +// // Weak ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter3, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); +// } +// break; + +// // +// case X121SMC_XWZ_PRIORITY_HIGH: +// // +// if (isSelectedZonDirBullish) +// { +// // +// // Weak ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter1, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); + +// // +// // High ... +// Add( +// workingZone.quarter3, +// targets // +// ); +// } +// else +// { +// // +// // Weak ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter3, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); + +// // +// // High ... +// Add( +// workingZone.quarter1, +// targets // +// ); +// } +// break; + +// // +// case X121SMC_XWZ_PRIORITY_STRONG_HIGH: +// // +// if (isSelectedZonDirBullish) +// { +// // +// // Weak ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter1, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); + +// // +// // High ... +// Add( +// workingZone.quarter3, +// targets // +// ); + +// // +// // Strong High ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); +// } +// else +// { +// // +// // Weak ... +// Add( +// workingZone.demandZone.Upper(), +// targets // +// ); + +// // +// // Low ... +// Add( +// workingZone.quarter3, +// targets // +// ); + +// // +// // Regular ... +// Add( +// workingZone.quarter2, +// targets // +// ); + +// // +// // High ... +// Add( +// workingZone.quarter1, +// targets // +// ); + +// // +// // Strong High ... +// Add( +// workingZone.supplyZone.Lower(), +// targets // +// ); +// } +// break; +// } +// } + +//////////////////////////////////////////////////////////////////// + +// +// Based On Consolidation Zones ... +has = isBarInited && + decisionState.HasConsolidationZones(); +if (has) +{ + // + XConsolidationZone tmpZones[]; + if (isSelectedZonDirBullish) + { + // + Copy( + decisionState.bullishConsolidationZones, + tmpZones // + ); + } + else + { + // + Copy( + decisionState.bearishConsolidationZones, + tmpZones // + ); + } + + // + while (HasChild(tmpZones)) + { + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + break; + } + + // + XConsolidationZone iZone = tmpZones[idx]; + + // + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + hasSelectedConsolidationZone = + isSelectedZonDirBullish + ? cBar.low < iZone.upper + : cBar.high < iZone.lower; + if (hasSelectedConsolidationZone) + { + // + selectedConsolidationZone = iZone; + iZone.Clean(); + break; + } + + // + iZone.Clean(); + } + + // + Clean(tmpZones); + + // + if (hasSelectedConsolidationZone) + { + // + XCConsolidationZoneObject *iObj; + selectedConsolidationZone.to = cTime; + bool isCreated = drawer.CreateConsolidationZone( + selectedConsolidationZone, + iObj // + ); + + // + double iSL = + isSelectedZonDirBullish + ? selectedConsolidationZone.lower + : selectedConsolidationZone.upper; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } +} + +// +// Based On Supply and Demand Zones ... + +// +// Demand Zones ... +has = hasWorkingZone && + workingZone.HasDemandZones(); +if (has) +{ + // + XCDemandZone *tmpZones[]; + Copy( + workingZone.demandZones, + tmpZones // + ); + XCDemandZone *selectedDemand = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetLowest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCDemandZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + isSelectedZonDirBullish + ? IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedDemand == NULL + ? true + : isSelectedZonDirBullish + ? selectedDemand.Lower() < iZone.Lower() + : selectedDemand.Upper() > iZone.Upper(); + if (!has) + { + continue; + } + + // + selectedDemand = iZone; + + // + } + + // + has = selectedDemand != NULL; + if (has) + { + // + XCDemandZoneObject *iObj; + bool isCreated = drawer.CreateDemandZone( + selectedDemand, + iObj // + ); + + // + double iSL = + isSelectedZonDirBullish + ? selectedDemand.Lower() + : selectedDemand.Upper(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedDemand); +} + +// +// Support Zones ... +has = hasWorkingZone && + workingZone.HasSupportZones(); +if (has) +{ + // + XCSupportZone *tmpZones[]; + Copy( + workingZone.supportZones, + tmpZones // + ); + XCSupportZone *selectedSupport = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetLowest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCSupportZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + isSelectedZonDirBullish + ? IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedSupport == NULL + ? true + : isSelectedZonDirBullish + ? selectedSupport.Lower() < iZone.Lower() + : selectedSupport.Upper() > iZone.Upper(); + if (!has) + { + continue; + } + + // + selectedSupport = iZone; + + // + } + + // + has = selectedSupport != NULL; + if (has) + { + // + XCSupportZoneObject *iObj; + bool isCreated = drawer.CreateSupportZone( + selectedSupport, + iObj // + ); + + // + double iSL = isSelectedZonDirBullish + ? selectedSupport.Lower() + : selectedSupport.Upper(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedSupport); +} + +// +// Supply Zones ... +has = hasWorkingZone && + workingZone.HasSupplyZones(); +if (has) +{ + // + XCSupplyZone *tmpZones[]; + Copy( + workingZone.supplyZones, + tmpZones // + ); + XCSupplyZone *selectedSupply = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetHighest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCSupplyZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + !isSelectedZonDirBullish + ? IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedSupply == NULL + ? true + : !isSelectedZonDirBullish + ? selectedSupply.Upper() > iZone.Upper() + : selectedSupply.Lower() < iZone.Lower(); + if (!has) + { + continue; + } + + // + selectedSupply = iZone; + + // + } + + // + has = selectedSupply != NULL; + if (has) + { + // + XCSupplyZoneObject *iObj; + bool isCreated = drawer.CreateSupplyZone( + selectedSupply, + iObj // + ); + + // + double iSL = + !isSelectedZonDirBullish + ? selectedSupply.Upper() + : selectedSupply.Lower(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedSupply); +} + +// +// Resistance Zones ... +has = hasWorkingZone && + workingZone.HasDemandZones(); +if (has) +{ + // + XCResistanceZone *tmpZones[]; + Copy( + workingZone.resistanceZones, + tmpZones // + ); + XCResistanceZone *selectedResistance = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetHighest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCResistanceZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + !isSelectedZonDirBullish + ? IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedResistance == NULL + ? true + : !isSelectedZonDirBullish + ? selectedResistance.Upper() < iZone.Upper() + : selectedResistance.Lower() > iZone.Lower(); + if (!has) + { + continue; + } + + // + selectedResistance = iZone; + + // + } + + // + has = selectedResistance != NULL; + if (has) + { + // + XCResistanceZoneObject *iObj; + bool isCreated = drawer.CreateResistanceZone( + selectedResistance, + iObj // + ); + + // + double iSL = + !isSelectedZonDirBullish + ? selectedResistance.Upper() + : selectedResistance.Lower(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedResistance); +} + +// +// Based On Passed Bars ... +XOHCL passedBar; +bool isPassed = false; +bool isBodyState = false; +ENUM_X_DIRECTION passedDir = selectedZone.GetDirection(); + +// +// Started Bar ... +isPassed = selectedZone.ob.IsStarted( + passedDir, + passedBar, + isBodyState // +); +if (isPassed) +{ + // + double iSL = + isSelectedZonDirBullish + ? passedBar.low + : passedBar.high; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } +} + +// +// Activation Bar ... +passedBar.Clean(); +isPassed = selectedZone.ob.IsActivated( + passedDir, + passedBar, + isBodyState // +); +if (isPassed) +{ + // + double iSL = + isSelectedZonDirBullish + ? passedBar.low + : passedBar.high; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } +} + +// +// Worked Bar ... +passedBar.Clean(); +isPassed = selectedZone.ob.IsActivated( + passedDir, + passedBar, + isBodyState // +); +if (isPassed) +{ + // + double iSL = + isSelectedZonDirBullish + ? passedBar.low + : passedBar.high; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } +} + +// +// Breaked Bar ... +passedBar.Clean(); +isPassed = selectedZone.ob.IsActivated( + passedDir, + passedBar, + isBodyState // +); +if (isPassed) +{ + // + double iSL = + isSelectedZonDirBullish + ? passedBar.low + : passedBar.high; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } +} + +//////////////////////////////////////////////////////////////////// + +// // +// // Trail Stops Using Swings ... + +// // +// bool canTrailLongUsingSwings = +// // +// isLong && +// isInProfit && +// (isSwingLow || +// isStrongSwingLow) && +// pBar.low > iPosition.sl && +// pBar.low > iPosition.entry +// // +// ; +// if (canTrailLongUsingSwings) +// { +// sl = pBar.low; +// } + +// // +// bool canTraiShortlUsingSwings = +// // +// !isLong && +// isInProfit && +// (isSwingHigh || +// isStrongSwingHigh) && +// pBar.high < iPosition.sl && +// pBar.high < iPosition.entry +// // +// ; +// if (canTraiShortlUsingSwings) +// { +// sl = pBar.high; +// } + +// // +// bool canTrailUsingSwings = +// canTrailLongUsingSwings || +// canTraiShortlUsingSwings; + +// // +// // +// // + +//////////////////////////////////////////////////////////////////////////// + +// // +// XOHCL zBar; +// result = zBar.Init( +// symbol, +// period, +// zIndex // +// ); +// if (!result) +// { +// // +// result = HasChild(guards); +// return result; +// } + +// // +// XOHCL cBar; +// result = cBar.Init( +// symbol, +// period, +// cIndex // +// ); +// if (!result) +// { +// // +// zBar.Clean(); +// result = HasChild(guards); +// return result; +// } + +// // +// XOHCL pBar; +// result = pBar.Init( +// symbol, +// period, +// pIndex // +// ); +// if (!result) +// { +// // +// zBar.Clean(); +// cBar.Clean(); +// result = HasChild(guards); +// return result; +// } + +// // +// XOHCL ppBar; +// result = ppBar.Init( +// symbol, +// period, +// ppIndex // +// ); +// if (!result) +// { +// // +// zBar.Clean(); +// cBar.Clean(); +// pBar.Clean(); +// result = HasChild(guards); +// return result; +// } + +// +// zBar.Clean(); +// cBar.Clean(); +// pBar.Clean(); +// ppBar.Clean(); + +// +// Detect High Probability Swings ... +// bool isSwingLow = +// // +// cBar.low > pBar.low && +// ppBar.low > pBar.low && +// // +// zBar.low > pBar.low +// // +// ; +// bool isSwingHigh = +// // +// cBar.high < pBar.high && +// ppBar.high < pBar.high && +// // +// zBar.high < pBar.high +// // +// ; +// bool isStrongSwingLow = +// pBar.IsBullish() && +// pBar.GetLowShadow() >= pBar.GetBody() * 2; +// bool isStrongSwingHigh = +// pBar.IsBearish() && +// pBar.GetHighShadow() >= pBar.GetBody() * 2; + +/////////////////////////////////////////////////////////////////////////////// + +// +// +// + +bool DetectX121Conditions( + double &pivot, + double &point, + double &sls[], + double &targets[], + ENUM_X_DIRECTION &dir, + XPOIState &stfState, + XPOIState &ttfState, + X121Conditions &conditions, + XCPOIDrawer *drawer = NULL // +) +{ + // + bool result = false; + + // + bool canDraw = drawer != NULL; + + // + pivot = 0; + point = 0; + Clean(sls); + Clean(targets); + dir = X_DIRECTION_NONE; + + // + result = + stfState.IsValid() && + ttfState.IsValid() && + stfState.HasChild() && + ttfState.HasChild(); + if (!result) + { + return result; + } + + // + int idx = -1; + int count = 0; + bool has = false; + + // + // Detect Inside STF Order Blocks Zones ... + + // + XOBFVG tmpWaitingZones[]; + count = ExtractOBFVGs( + tmpWaitingZones, + stfState, + ttfState // + ); + has = IsValidSize(count); + if (has) + { + // + if (canDraw) + { + // + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = tmpWaitingZones[i]; + + // + iOBFVG.UpdateTo(); + + // + XCBaseObject *iOBFVGObjects[]; + int iOBFVGObjectsCount = drawer.DrawOBFVG( + iOBFVG, + iOBFVGObjects // + ); + } + } + } + + // + + // + return result; +} + +////////////////////////////////////////////////////////////////////////// + +/** + * Check an XOBFVG instance has Required Conditions ... + * + * @param zone: XBoxZone instance ... + * @param state: XPOIState instance ... + * @param conditions: X121Conditions instance ... + * + * @return ( bool ) + */ +bool DetectSelectedBoxConditions( + bool &isReversal, + XBoxZone &zone, + XPOIState &state, + X121Conditions &conditions // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + result = + zone.IsValid() && + state.IsValid() && + state.HasChild(); + if (!result) + { + return result; + } + + // + bool isBullish = zone.IsBullish(); + bool isBearish = zone.IsBearish(); + + // + bool isBullishTrend = conditions.isTrendBullish || + conditions.isTrendSwitchedToBullish; + bool isBearishTrend = conditions.isTrendBearish || + conditions.isTrendSwitchedToBearish; + + // + double bullishScore = 0; + double bearishScore = 0; + double scoreMultiplier = 1.5; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + + // + bool isBullishScorePassed = bullishScore > 0 && + bearishScore >= 0 && + bullishScore > bearishScore * scoreMultiplier; + + // + bool isBearishScorePassed = bearishScore > 0 && + bullishScore >= 0 && + bearishScore > bullishScore * scoreMultiplier; + + // + // VWap ... + + // + double vwapFast = conditions.vwapFastBuffer[0]; + double vwapMid = conditions.vwapMidBuffer[0]; + double vwapSlow = conditions.vwapSlowBuffer[0]; + + // + bool isVWapInside = + // + vwapFast > zone.lower && + vwapFast < zone.upper + // + && + vwapMid > zone.lower && + vwapMid < zone.upper + // + ; + + // + bool isVWapBullish = + // + (conditions.isVWapBullishState && + conditions.isVWapSwitchedToBullishOrdered) + // + || + // + (conditions.isVWapBullishOrdered && + conditions.isVWapSwitchedToBullishState) + // + ; + + // + bool isVWapBearish = + // + (conditions.isVWapBearishState && + conditions.isVWapSwitchedToBearishOrdered) + // + || + // + (conditions.isVWapBearishOrdered && + conditions.isVWapSwitchedToBearishState) + // + ; + + // + // X3Ma ... + + // + double x3maFast = conditions.x3maFastBuffer[0]; + double x3maMid = conditions.x3maMidBuffer[0]; + double x3maSlow = conditions.x3maSlowBuffer[0]; + + // + bool isX3MaInside = + // + x3maFast > zone.lower && + x3maFast < zone.upper + // + && + x3maMid > zone.lower && + x3maMid < zone.upper + // + ; + + // + bool isX3MaBullish = + // + (conditions.isX3MaBullishState && + conditions.isX3MaSwitchedToBullishOrdered) + // + || + // + (conditions.isX3MaBullishOrdered && + conditions.isX3MaSwitchedToBullishState) + // + ; + + // + bool isX3MaBearish = + // + (conditions.isX3MaBearishState && + conditions.isX3MaSwitchedToBearishOrdered) + // + || + // + (conditions.isX3MaBearishOrdered && + conditions.isX3MaSwitchedToBearishState) + // + ; + + // + // + // + + // + bool isInside = + // + isVWapInside || + isX3MaInside + // + ; + + // + bool isVWap3MaBullish = + isVWapBullish || + isX3MaBullish; + + // + bool isVWap3MaBearish = + isVWapBearish || + isX3MaBearish; + + // + // + // + + // + bool isDirectionalBullishPassed = + // + isInside && + isBullish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isDirectionalBearishPassed = + // + isInside && + isBearish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isDirectionalPassed = + isDirectionalBullishPassed || + isDirectionalBearishPassed; + + // + bool isReversalBullishPassed = + // + isInside && + isBullish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isReversalBearishPassed = + // + isInside && + isBearish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isReversalPassed = isReversalBullishPassed || + isReversalBearishPassed; + + // + result = isReversalPassed || + isDirectionalPassed; + + // + if (result) + { + isReversal = isReversalPassed; + } + + // + return result; +} + +/////////////////////////////////////////////////////////////////////////////// + +// if (hasWaitingZones) +// { +// // +// int idx = -1; +// int count = 0; +// XOBFVG youngest; +// bool has = false; +// XCFVG *selectedFVG; +// XCFVG *unActivatedFVGs[]; + +// // +// idx = GetYoungest(workingZone.waitingZones); +// has = IsValidIndex(idx); +// if (has) +// { +// // +// youngest = workingZone.waitingZones[idx]; +// selectedZoneDir = youngest.GetDirection(); + +// // +// if (IsBullish(selectedZoneDir)) +// { +// // +// Copy( +// analyseState.bullishFairValueGaps, +// unActivatedFVGs // +// ); +// } +// else +// { +// // +// Copy( +// analyseState.bearishFairValueGaps, +// unActivatedFVGs // +// ); +// } +// } + +// // +// count = ArraySize(unActivatedFVGs); +// has = IsValidSize(count); +// if (has) +// { +// // +// idx = GetYoungest(unActivatedFVGs); +// has = IsValidIndex(idx); +// if (has) +// { +// selectedFVG = unActivatedFVGs[idx]; +// } +// } + +// // +// has = selectedFVG != NULL; +// if (has) +// { +// // +// XCBaseObject *iObj; +// bool isCreated = drawer.CreateFairValueGap( +// selectedFVG, +// iObj // +// ); + +// // +// if (isCreated) +// { +// Print("Salam"); +// } +// } +// } + +////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Check an XOBFVG instance has Required Conditions ... + * + * @param zone: XOBFVG instance ... + * @param state: XPOIState instance ... + * @param conditions: X121Conditions instance ... + * + * @return ( bool ) + */ +bool DetectInsideSelectedZoneConditions( + bool &isReversal, + XOBFVG &zone, + XPOIState &state, + X121Conditions &conditions // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + result = + zone.IsValid() && + state.IsValid() && + state.HasChild(); + if (!result) + { + return result; + } + + // + bool isBullish = zone.IsBullish(); + bool isBearish = zone.IsBearish(); + + // + bool isBullishTrend = conditions.isTrendBullish || + conditions.isTrendSwitchedToBullish; + bool isBearishTrend = conditions.isTrendBearish || + conditions.isTrendSwitchedToBearish; + + // + double bullishScore = 0; + double bearishScore = 0; + double scoreMultiplier = 1.5; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + + // + bool isBullishScorePassed = bullishScore > 0 && + bearishScore >= 0 && + bullishScore > bearishScore * scoreMultiplier; + + // + bool isBearishScorePassed = bearishScore > 0 && + bullishScore >= 0 && + bearishScore > bullishScore * scoreMultiplier; + + // + // VWap ... + + // + double vwapFast = conditions.vwapFastBuffer[0]; + double vwapMid = conditions.vwapMidBuffer[0]; + double vwapSlow = conditions.vwapSlowBuffer[0]; + + // + bool isVWapInside = + // + vwapFast > zone.ob.Lower() && + vwapFast < zone.ob.Upper() + // + && + vwapMid > zone.ob.Lower() && + vwapMid < zone.ob.Upper() + // + ; + + // + bool isVWapBullish = + // + (conditions.isVWapBullishState && + conditions.isVWapSwitchedToBullishOrdered) + // + || + // + (conditions.isVWapBullishOrdered && + conditions.isVWapSwitchedToBullishState) + // + ; + + // + bool isVWapBearish = + // + (conditions.isVWapBearishState && + conditions.isVWapSwitchedToBearishOrdered) + // + || + // + (conditions.isVWapBearishOrdered && + conditions.isVWapSwitchedToBearishState) + // + ; + + // + // X3Ma ... + + // + double x3maFast = conditions.x3maFastBuffer[0]; + double x3maMid = conditions.x3maMidBuffer[0]; + double x3maSlow = conditions.x3maSlowBuffer[0]; + + // + bool isX3MaInside = + // + x3maFast > zone.ob.Lower() && + x3maFast < zone.ob.Upper() + // + && + x3maMid > zone.ob.Lower() && + x3maMid < zone.ob.Upper() + // + ; + + // + bool isX3MaBullish = + // + (conditions.isX3MaBullishState && + conditions.isX3MaSwitchedToBullishOrdered) + // + || + // + (conditions.isX3MaBullishOrdered && + conditions.isX3MaSwitchedToBullishState) + // + ; + + // + bool isX3MaBearish = + // + (conditions.isX3MaBearishState && + conditions.isX3MaSwitchedToBearishOrdered) + // + || + // + (conditions.isX3MaBearishOrdered && + conditions.isX3MaSwitchedToBearishState) + // + ; + + // + // + // + + // + bool isInside = + // + isVWapInside || + isX3MaInside + // + ; + + // + bool isVWap3MaBullish = + isVWapBullish || + isX3MaBullish; + + // + bool isVWap3MaBearish = + isVWapBearish || + isX3MaBearish; + + // + // + // + + // + bool isDirectionalBullishPassed = + // + isInside && + isBullish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isDirectionalBearishPassed = + // + isInside && + isBearish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isDirectionalPassed = + isDirectionalBullishPassed || + isDirectionalBearishPassed; + + // + bool isReversalBullishPassed = + // + isInside && + isBullish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isReversalBearishPassed = + // + isInside && + isBearish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isReversalPassed = isReversalBullishPassed || + isReversalBearishPassed; + + // + result = isReversalPassed || + isDirectionalPassed; + + // + if (result) + { + isReversal = isReversalPassed; + } + + // + return result; +} + +bool DetectBreakedSelectedZoneConditions( + bool &isReversal, + XOBFVG &zone, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState, + X121Conditions &conditions // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + result = + // + zone.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + ttfState.IsValid() && + mtfState.HasChild() && + stfState.HasChild() && + ttfState.HasChild() + // + ; + if (!result) + { + return result; + } + + // + XBoxZone iBox; + result = ToBox( + iBox, + zone.ob // + ); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + bool isBearish = IsBearish(iDir); + + // + // X3Ma ... + + // + double x3maFast = conditions.x3maFastBuffer[0]; + double x3maMid = conditions.x3maMidBuffer[0]; + double x3maSlow = conditions.x3maSlowBuffer[0]; + + // + bool isX3mInside = + // + (x3maFast < iBox.upper && + x3maMid < iBox.upper && + x3maSlow < iBox.upper) + // + && + // + (x3maFast > iBox.lower && + x3maMid > iBox.lower && + x3maSlow > iBox.lower) + // + ; + + // + bool isBullishConditions = + isBullish && + isX3mInside; + + // + bool isBearishConditions = + isBearish && + isX3mInside; + + // + result = isBullishConditions || + isBearishConditions; + + // + return result; +} + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + XOBFVG tmpZones[]; + + // + // Based On Waiting Zones ... + has = workingZone.HasWaitingZones(); + if (has) + { + // + Copy( + workingZone.waitingZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Breaked Zones ... + has = workingZone.HasBreakedZones(); + if (has) + { + Copy( + workingZone.breakedZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XBoxZone instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XBoxZone &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + XOBFVG tmpZones[]; + + // + // Based On Waiting Zones ... + has = workingZone.HasWaitingZones(); + if (has) + { + // + Copy( + workingZone.waitingZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Breaked Zones ... + has = workingZone.HasBreakedZones(); + if (has) + { + Copy( + workingZone.breakedZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +/** + * Detect SL Candidates Based on Selected Zone for Specified type of Directions ... + * + * @param sls: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingZone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * @param maxAllowedSLDistanceInPoint: doube max Allowe SL distance ... + * + * @return ( bool ) + */ +bool DetectSelectedZoneSLCandidates( + double &sls[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + X121SMCStrategyXWZWorkingZone &workingZone, + X121Conditions &conditions, + int barIndex = 0, + double maxAllowedSLDistanceInPoint = 300 // +) +{ + // + bool result = false; + + // + Clean(sls); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + double pivot = + isBullish + ? selectedZone.ob.Lower() + : selectedZone.ob.Upper(); + double points = GetPoints(workingZone.symbol); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + + // + double pvSL = isBullish + ? conditions.valesBuffer[0] + : conditions.peaksBuffer[1]; + + // + Add( + pvSL, + sls // + ); + + // + // Based On Passed Bars ... + // XOHCL passedBar; + // bool isPassed = false; + // bool isBodyState = false; + // ENUM_X_DIRECTION passedDir = selectedZone.GetDirection(); + + // // + // // Started Bar ... + // isPassed = selectedZone.ob.IsStarted( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Activation Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Worked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Breaked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // + // Based On Consolidation Zones ... + has = workingZone.HasConsolidationZones(); + if (has) + { + // + XConsolidationZone tmpZones[]; + Copy( + workingZone.consolidationZones, + tmpZones // + ); + XConsolidationZone selectedConsolidationZone; + + // + while (HasChild(tmpZones)) + { + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + break; + } + + // + XConsolidationZone iZone = tmpZones[idx]; + + // + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + has = + !selectedConsolidationZone.IsValid() + ? isBullish + ? cBar.low < iZone.upper + : cBar.high < iZone.lower + : isBullish + ? selectedConsolidationZone.lower < iZone.lower + : selectedConsolidationZone.upper > iZone.upper; + if (has) + { + // + selectedConsolidationZone = iZone; + iZone.Clean(); + break; + } + + // + iZone.Clean(); + } + + // + Clean(tmpZones); + has = selectedConsolidationZone.IsValid(); + if (has) + { + // + double iSL = + isBullish + ? selectedConsolidationZone.lower + : selectedConsolidationZone.upper; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + } + + // + // Based On Supply and Demand Zones ... + + // + // Demand Zones ... + has = workingZone.HasDemandZones(); + if (has) + { + // + XCDemandZone *tmpZones[]; + Copy( + workingZone.demandZones, + tmpZones // + ); + XCDemandZone *selectedDemand = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetLowest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCDemandZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + isBullish + ? IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedDemand == NULL + ? true + : isBullish + ? selectedDemand.Lower() < iZone.Lower() + : selectedDemand.Upper() > iZone.Upper(); + if (!has) + { + continue; + } + + // + selectedDemand = iZone; + } + + // + has = selectedDemand != NULL; + if (has) + { + // + double iSL = + isBullish + ? selectedDemand.Lower() + : selectedDemand.Upper(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedDemand); + } + + // + // Support Zones ... + // has = workingZone.HasSupportZones(); + // if (has) + // { + // // + // XCSupportZone *tmpZones[]; + // Copy( + // workingZone.supportZones, + // tmpZones // + // ); + // XCSupportZone *selectedSupport = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetLowest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCSupportZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // isBullish + // ? IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedSupport == NULL + // ? true + // : isBullish + // ? selectedSupport.Lower() < iZone.Lower() + // : selectedSupport.Upper() > iZone.Upper(); + // if (!has) + // { + // continue; + // } + + // // + // selectedSupport = iZone; + + // // + // } + + // // + // has = selectedSupport != NULL; + // if (has) + // { + // // + // double iSL = isBullish + // ? selectedSupport.Lower() + // : selectedSupport.Upper(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedSupport); + // } + + // + // Supply Zones ... + has = workingZone.HasSupplyZones(); + if (has) + { + // + XCSupplyZone *tmpZones[]; + Copy( + workingZone.supplyZones, + tmpZones // + ); + XCSupplyZone *selectedSupply = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetHighest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCSupplyZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + !isBullish + ? IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedSupply == NULL + ? true + : !isBullish + ? selectedSupply.Upper() > iZone.Upper() + : selectedSupply.Lower() < iZone.Lower(); + if (!has) + { + continue; + } + + // + selectedSupply = iZone; + + // + } + + // + has = selectedSupply != NULL; + if (has) + { + // + double iSL = + !isBullish + ? selectedSupply.Upper() + : selectedSupply.Lower(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedSupply); + } + + // + // Resistance Zones ... + // has = workingZone.HasDemandZones(); + // if (has) + // { + // // + // XCResistanceZone *tmpZones[]; + // Copy( + // workingZone.resistanceZones, + // tmpZones // + // ); + // XCResistanceZone *selectedResistance = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetHighest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCResistanceZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // !isBullish + // ? IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedResistance == NULL + // ? true + // : !isBullish + // ? selectedResistance.Upper() < iZone.Upper() + // : selectedResistance.Lower() > iZone.Lower(); + // if (!has) + // { + // continue; + // } + + // // + // selectedResistance = iZone; + + // // + // } + + // // + // has = selectedResistance != NULL; + // if (has) + // { + // // + // double iSL = + // !isBullish + // ? selectedResistance.Upper() + // : selectedResistance.Lower(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedResistance); + // } + + // + // Cleanp Resources ... + + // + cBar.Clean(); + // passedBar.Clean(); + result = HasChild(sls); + + // + return result; +} + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XBoxZone instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XBoxZone &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + XOBFVG tmpZones[]; + + // + // Based On Waiting Zones ... + has = workingZone.HasWaitingZones(); + if (has) + { + // + Copy( + workingZone.waitingZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Breaked Zones ... + has = workingZone.HasBreakedZones(); + if (has) + { + Copy( + workingZone.breakedZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +/////////////////////////////////////////////////////////////////////// + +// +struct X121SMCStrategyXWZWorkingZone +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double quarter1; + double quarter2; + double quarter3; + + // + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + + // + XCSupplyZone *supplyZones[]; + XCDemandZone *demandZones[]; + + // + XCSupportZone *supportZones[]; + XCResistanceZone *resistanceZones[]; + + // + XOBFVG insideZones[]; + XOBFVG breakedZones[]; + XOBFVG waitingZones[]; + + // + XBoxZone insideBoxes[]; + XBoxZone breakedBoxes[]; + XConsolidationZone consolidationZones[]; + + // + CArrayObj mInsideZoneObjects; + CArrayObj mBreakedZoneObjects; + CArrayObj mWaitingZoneObjects; + CArrayObj mWorkingZoneObjects; + + // + // Constructor ... + X121SMCStrategyXWZWorkingZone() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + quarter1 = 0; + quarter2 = 0; + quarter3 = 0; + + // + symbol = NULL; + period = NULL; + + // + Clean(supplyZones); + Clean(demandZones); + + // + Clean(insideZones); + Clean(waitingZones); + Clean(breakedZones); + + // + Clean(insideBoxes); + Clean(breakedBoxes); + + // + Clean(supportZones); + Clean(resistanceZones); + + // + ZeroMemory(supplyZone); + ZeroMemory(demandZone); + + // + mInsideZoneObjects.Clear(); + mBreakedZoneObjects.Clear(); + mWaitingZoneObjects.Clear(); + mWorkingZoneObjects.Clear(); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + // + quarter1 > 0 && + quarter2 > 0 && + quarter3 > 0 && + HasSupplyZone() && + HasDemandZone() && + quarter1 > quarter2 && + quarter2 > quarter3 + // + ; + + // + return result; + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, // + XPOIState &ttfState // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + ttfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() && + ttfState.HasChild() + // + ; + if (!result) + { + return result; + } + + // + symbol = _symbol; + period = _period; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + result = has; + if (!result) + { + zBar.Clean(); + return result; + } + double ll5 = zBar.FindLowest(5, MODE_LOW); + double hh5 = zBar.FindHighest(5, MODE_HIGH); + zBar.Clean(); + + // + // Supply Zone ... + has = HasSupplyZone(); + if (!has) + { + // + idx = GetHighest(htfState.supplyZones); + has = IsValidIndex(idx); + if (has) + { + // + supplyZone = htfState.supplyZones[idx]; + has = hh5 < supplyZone.Lower(); + if (!has) + { + supplyZone = NULL; + } + } + } + + // + // Demand Zone ... + has = HasDemandZone(); + if (!has) + { + // + idx = GetLowest(htfState.demandZones); + has = IsValidIndex(idx); + if (has) + { + // + demandZone = htfState.demandZones[idx]; + has = ll5 > demandZone.Upper(); + if (!has) + { + demandZone = NULL; + } + } + } + + // + // Supply Zones ... + has = HasSupplyZones(); + if (!has) + { + // + count = mtfState.FilterSupplyZones( + supplyZones, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + } + + // + // Demand Zones ... + has = HasDemandZones(); + if (!has) + { + // + count = mtfState.FilterDemandZones( + demandZones, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + } + + // + has = ttfState.HasConsolidationZones(); + if (has) + { + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); + } + + // + if (supplyZone != NULL && + demandZone != NULL && + supplyZone.IsValid() && + demandZone.IsValid()) + { + // + double upper = supplyZone.Lower(); + double lower = demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + quarter1 = upper - (1 * delta); + quarter2 = upper - (2 * delta); + quarter3 = upper - (3 * delta); + } + + // + // Detect OBFVG(s) ... + ExtractOBFVGs( + waitingZones, + mtfState, + stfState); + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + // + void Update( + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState // + ) + { + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + has = + // + IsValid() && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() + // + ; + if (!has) + { + return; + } + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + zBar.Clean(); + return; + } + + // + XOHCL cBar; + has = zBar.GetPreviousBar(cBar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + + // + return; + } + + // + // Adding New OBFVG to Waiting Zones if not Exists ... + XOBFVG tmpWaitingZones[]; + count = ExtractOBFVGs( + tmpWaitingZones, + mtfState, + stfState // + ); + has = IsValidSize(count); + if (has) + { + // + AddIfNotExists( + tmpWaitingZones, + waitingZones // + ); + } + + // + // Since Usig States for Extracting Supply/Demand or + // Support/Resistance Zones and State's has Max Alllowed Restrication ... + // we have to Manage new Zones and also Hold's Breaked Zones ... + + // + // MTF STF ... + + // + // Supply Zones ... + XCSupplyZone *tmpSupplies[]; + count = mtfState.FilterSupplyZones( + tmpSupplies, + NULL, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + tmpSupplies[i] // + ); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Find Index ... + + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + tmpSupplies[i], + supplyZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Checking Price Validation ... + has = cBar.high < tmpSupplies[i].Lower(); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + Add( + tmpSupplies[i], + supplyZones // + ); + + // + iBox.Clean(); + } + } + Clean(tmpSupplies); + + // + // Demand Zones ... + XCDemandZone *tmpDemands[]; + count = mtfState.FilterDemandZones( + tmpDemands, + NULL, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + tmpDemands[i] // + ); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Find Index ... + + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + tmpDemands[i], + demandZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Checking Price Validation ... + has = cBar.low > tmpDemands[i].Upper(); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + Add( + tmpDemands[i], + demandZones // + ); + + // + iBox.Clean(); + } + } + Clean(tmpDemands); + + // + // + // + + // + // Consolidation Zones ... + has = ttfState.HasConsolidationZones(); + if (has) + { + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); + } + + // + // + // + + // + // Detect Price Inside Zones ... + has = HasWaitingZones(); + if (has) + { + // + int mustRemove[]; + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = waitingZones[i]; + + // + bool isInside = + // + zBar.high < iOBFVG.ob.Upper() && + zBar.low > iOBFVG.ob.Lower() && + // + cBar.high < iOBFVG.ob.Upper() && + cBar.low > iOBFVG.ob.Lower() + // + ; + if (isInside) + { + // + idx = FindIndex( + iOBFVG, + insideZones // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iOBFVG, + insideZones // + ); + } + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + waitingZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Here we Looking for Price Inside Supply or Demand Zones ... + + // + // Supply Zones ... + has = HasSupplyZones(); + if (has) + { + // + int mustRemove[]; + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = supplyZones[i]; + + // + bool isInside = + // + zBar.high < iZone.Upper() && + zBar.low > iZone.Lower() && + // + cBar.high < iZone.Upper() && + cBar.low > iZone.Lower() + // + ; + if (isInside) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + iZone // + ); + if (has) + { + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iBox, + insideBoxes // + ); + } + } + + // + iBox.Clean(); + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + supplyZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Demand Zones ... + has = HasDemandZones(); + if (has) + { + // + int mustRemove[]; + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = demandZones[i]; + + // + bool isInside = + // + zBar.high < iZone.Upper() && + zBar.low > iZone.Lower() && + // + cBar.high < iZone.Upper() && + cBar.low > iZone.Lower() + // + ; + if (isInside) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + iZone // + ); + if (has) + { + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iBox, + insideBoxes // + ); + } + } + + // + iBox.Clean(); + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + demandZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Here we Detect Breaked Zone/Box (s) ... + + // // + // // Detect Breaked Zones ... + // has = HasInsideZones(); + // if (has) + // { + // // + // int mustRemove[]; + // count = CountInsideZones(); + // for (int i = 0; i < count; i++) + // { + // // + // XOBFVG iOBFVG = insideZones[i]; + // ENUM_X_DIRECTION iDir = iOBFVG.GetDirection(); + // bool isBullish = IsBullish(iDir); + + // // + // bool isBullishBreaked = + // // + // zBar.high < iOBFVG.ob.Lower() && + // cBar.high < iOBFVG.ob.Lower() + // // + // ; + + // // + // bool isBearishBreaked = + // // + // zBar.low > iOBFVG.ob.Upper() && + // cBar.low > iOBFVG.ob.Upper() + // // + // ; + + // // + // bool isBreaked = + // isBullish + // ? isBullishBreaked + // : isBearishBreaked; + + // // + // if (isBreaked) + // { + // // + // idx = FindIndex( + // iOBFVG, + // breakedZones // + // ); + // has = IsValidIndex(idx); + // if (!has) + // { + // // + // Add( + // i, + // mustRemove // + // ); + + // // + // AddRef( + // iOBFVG, + // breakedZones // + // ); + // } + // } + // } + + // // + // has = HasChild(mustRemove); + // if (has) + // { + // // + // count = ArraySize(mustRemove); + // for (int i = 0; i < count; i++) + // { + // // + // ArrayRemove( + // insideZones, + // mustRemove[i], + // 1 // + // ); + // } + // } + + // // + // Clean(mustRemove); + // } + + // // + // // Detect Breaked Boxes ... + // has = HasInsideBoxes(); + // if (has) + // { + // // + // int mustRemove[]; + // count = CountInsideBoxes(); + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox = insideBoxes[i]; + // ENUM_X_DIRECTION iDir = iBox.dir; + // bool isBullish = iBox.IsBullish(); + + // // + // bool isBullishBreaked = + // // + // zBar.high < iBox.lower && + // cBar.high < iBox.lower + // // + // ; + + // // + // bool isBearishBreaked = + // // + // zBar.low > iBox.upper && + // cBar.low > iBox.upper + // // + // ; + + // // + // bool isBreaked = + // isBullish + // ? isBullishBreaked + // : isBearishBreaked; + + // // + // if (isBreaked) + // { + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = IsValidIndex(idx); + // if (!has) + // { + // // + // Add( + // i, + // mustRemove // + // ); + + // // + // AddRef( + // iBox, + // breakedBoxes // + // ); + // } + // } + // } + + // // + // has = HasChild(mustRemove); + // if (has) + // { + // // + // count = ArraySize(mustRemove); + // for (int i = 0; i < count; i++) + // { + // // + // ArrayRemove( + // insideBoxes, + // mustRemove[i], + // 1 // + // ); + // } + // } + + // // + // Clean(mustRemove); + // } + + // + // Cleanup Resource ... + + // + zBar.Clean(); + cBar.Clean(); + } + + // + bool HasSupplyZone() + { + return supplyZone != NULL && + supplyZone.IsValid(); + } + + // + bool HasDemandZone() + { + return demandZone != NULL && + demandZone.IsValid(); + } + + // + bool HasSupplyZones() + { + return HasChild(supplyZones); + } + + // + int CountSupplyZones() + { + return ArraySize(supplyZones); + } + + // + bool HasDemandZones() + { + return HasChild(demandZones); + } + + // + int CountDemandZones() + { + return ArraySize(demandZones); + } + + // + bool HasSupportZones() + { + return HasChild(supportZones); + } + + // + int CountSupportZones() + { + return ArraySize(supportZones); + } + + // + bool HasResistanceZones() + { + return HasChild(resistanceZones); + } + + // + int CountResistanceZones() + { + return ArraySize(resistanceZones); + } + + // + bool HasWaitingZones() + { + return HasChild(waitingZones); + } + + // + int CountWaitingZones() + { + return ArraySize(waitingZones); + } + + // + bool HasInsideZones() + { + return HasChild(insideZones); + } + + // + int CountInsideZones() + { + return ArraySize(insideZones); + } + + // + bool HasBreakedZones() + { + return HasChild(breakedZones); + } + + // + int CountBreakedZones() + { + return ArraySize(breakedZones); + } + + // + bool HasConsolidationZones() + { + return HasChild(consolidationZones); + } + + // + int CountConsolidationZones() + { + return ArraySize(consolidationZones); + } + + // + bool HasInsideBoxes() + { + return HasChild(insideBoxes); + } + + // + int CountInsideBoxes() + { + return ArraySize(insideBoxes); + } + + // + bool HasBreakedBoxes() + { + return HasChild(breakedBoxes); + } + + // + int CountBreakedBoxes() + { + return ArraySize(breakedBoxes); + } + + // + // + // + + // + bool IsDestroyed( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL cBar; + result = bar.GetPreviousBar(cBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + bool isSupplyZoneBreaked = + // + bar.low > supplyZone.Upper() && + cBar.low > supplyZone.Upper() + // + ; + + // + bool isDemandZoneBreaked = + // + bar.high < demandZone.Lower() && + cBar.high < demandZone.Lower() + // + ; + + // + bar.Clean(); + cBar.Clean(); + + // + result = isSupplyZoneBreaked || + isDemandZoneBreaked; + + // + return result; + } + + // + bool DetectPriority( + ENUM_X121SMC_XWZ_PRIORITY &priority, + ENUM_X_DIRECTION forDir, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + priority = X121SMC_XWZ_PRIORITY_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + if (bar.high < supplyZone.Upper() && + bar.low > supplyZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_NONE + : X121SMC_XWZ_PRIORITY_STRONG_HIGH; + } + else if (bar.high < supplyZone.Lower() && + bar.low > quarter1) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_WEAK + : X121SMC_XWZ_PRIORITY_HIGH; + } + else if (bar.high < quarter1 && + bar.low > quarter2) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_LOW + : X121SMC_XWZ_PRIORITY_REGULAR; + } + else if (bar.high < quarter2 && + bar.low > quarter3) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_REGULAR + : X121SMC_XWZ_PRIORITY_LOW; + } + else if (bar.high < quarter3 && + bar.low > demandZone.Upper()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_HIGH + : X121SMC_XWZ_PRIORITY_WEAK; + } + else if (bar.high < demandZone.Upper() && + bar.low > demandZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_STRONG_HIGH + : X121SMC_XWZ_PRIORITY_NONE; + } + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE && + priority != X121SMC_XWZ_PRIORITY_WEAK; + + // + bar.Clean(); + + // + return result; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasSupplyZone(); + if (has) + { + supplyZone.To(value); + } + + // + has = HasDemandZone(); + if (has) + { + demandZone.To(value); + } + + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } + } + + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } + } + + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + supportZones[i].To(value); + } + } + + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + resistanceZones[i].To(value); + } + } + + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + waitingZones[i].UpdateTo(value); + } + } + + // + has = HasInsideZones(); + if (has) + { + // + count = CountInsideZones(); + for (int i = 0; i < count; i++) + { + insideZones[i].UpdateTo(value); + } + } + + // + has = HasInsideBoxes(); + if (has) + { + // + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + insideBoxes[i].to = value; + } + } + + // + } + + // + void Draw( + XCPOIDrawer *drawer, + bool drawWaitingZones = true, + bool drawInsideZones = false, + bool drawBreakedZones = false, + bool drawSupplyZone = false, + bool drawDemandZone = false, + bool drawSupplyZones = false, + bool drawDemandZones = false, + bool drawSupportZones = false, + bool drawResistanceZones = false // + ) + { + // + if (drawer == NULL) + { + return; + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + ulong chartID = drawer.ChartIdentification(); + int subWindow = drawer.SubWindowIdentification(); + color bullishColor = drawer.BarBullishColor(); + color bearishColor = drawer.BarBearishColor(); + + // + // Supply Zone ... + if (drawSupplyZone) + { + // + has = HasSupplyZone(); + if (has) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Demand Zone ... + if (drawDemandZone) + { + // + has = HasDemandZone(); + if (has) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // + // + + // + // Supply Zones ... + if (drawSupplyZones) + { + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Demand Zones ... + if (drawDemandZones) + { + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Support Zones ... + if (drawSupportZones) + { + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = drawer.CreateSupportZone( + supportZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Resistance Zones ... + if (drawResistanceZones) + { + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = drawer.CreateResistanceZone( + resistanceZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // + // + + // + // Waiting Zones ... + if (drawWaitingZones) + { + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + waitingZones[i], + objects // + ); + has = IsValidSize(objectsCount); + if (has) + { + // + for (int j = 0; j < objectsCount; j++) + { + mWaitingZoneObjects.Add(objects[j]); + } + } + } + } + } + + // + // Inside Zones ... + if (drawInsideZones) + { + // + // Zones ... + has = HasInsideZones(); + if (has) + { + // + count = CountInsideZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + insideZones[i], + objects // + ); + + // + has = IsValidSize(objectsCount); + if (has) + { + // + for (int i = 0; i < objectsCount; i++) + { + mInsideZoneObjects.Add(objects[i]); + } + } + } + } + + // // + // // Boxes ... + // has = HasInsideBoxes(); + // if (has) + // { + // // + // count = CountInsideBoxes(); + // for (int i = 0; i < count; i++) + // { + // // + // XCBoxObject *object; + // bool isCreated = drawer.DrawBox( + // insideBoxes[i], + // object // + // ); + + // // + // if (isCreated) + // { + // mInsideZoneObjects.Add(object); + // } + // } + // } + } + + // + // Breaked Zones ... + if (drawBreakedZones) + { + // + has = HasBreakedZones(); + if (has) + { + // + count = CountBreakedZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + breakedZones[i], + objects // + ); + + // + has = IsValidSize(objectsCount); + if (has) + { + // + for (int i = 0; i < objectsCount; i++) + { + mBreakedZoneObjects.Add(objects[i]); + } + } + } + } + + // // + // // Boxes ... + // has = HasBreakedBoxes(); + // if (has) + // { + // // + // count = CountBreakedBoxes(); + // for (int i = 0; i < count; i++) + // { + // // + // XCBoxObject *object; + // bool isCreated = drawer.DrawBox( + // breakedBoxes[i], + // object // + // ); + + // // + // if (isCreated) + // { + // mInsideZoneObjects.Add(object); + // } + // } + // } + } + + // + // + // + + // + // Quarters ... + has = IsValid(); + if (has) + { + // + double zoneUpper = supplyZone.Upper(); + double upper = supplyZone.Lower(); + + // + double lower = demandZone.Upper(); + double zoneLower = demandZone.Lower(); + + // + string prefix = "X121WZone_" + symbol + "_" + ToString(period); + + // + // Zone Upper ... + CChartObjectHLine *zoneUpperLine; + zoneUpperLine = new CChartObjectHLine(); + isCreated = zoneUpperLine.Create( + chartID, + prefix + "_ZoneTop", + subWindow, + zoneUpper // + ); + if (isCreated) + { + // + zoneUpperLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneUpperLine); + } + + // + // Zone Lower ... + CChartObjectHLine *zoneLowerLine; + zoneLowerLine = new CChartObjectHLine(); + isCreated = zoneLowerLine.Create( + chartID, + prefix + "_ZoneDown", + subWindow, + zoneLower // + ); + if (isCreated) + { + // + zoneLowerLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneLowerLine); + } + + // + // Upper ... + CChartObjectHLine *upperLine; + upperLine = new CChartObjectHLine(); + isCreated = upperLine.Create( + chartID, + prefix + "_Upper", + subWindow, + upper // + ); + if (isCreated) + { + // + upperLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(upperLine); + } + + // + // Lower ... + CChartObjectHLine *lowerLine; + lowerLine = new CChartObjectHLine(); + isCreated = lowerLine.Create( + chartID, + prefix + "_Lower", + subWindow, + lower // + ); + if (isCreated) + { + // + lowerLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(lowerLine); + } + + // + // Quarters ... + + // + // Quarter 1 ... + CChartObjectHLine *q1Line; + q1Line = new CChartObjectHLine(); + isCreated = q1Line.Create( + chartID, + prefix + "_Q1", + subWindow, + quarter1 // + ); + if (isCreated) + { + // + q1Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q1Line); + } + + // + // Quarter 2 ... + CChartObjectHLine *q2Line; + q2Line = new CChartObjectHLine(); + isCreated = q2Line.Create( + chartID, + prefix + "_Q2", + subWindow, + quarter2 // + ); + if (isCreated) + { + // + q2Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q2Line); + } + + // + // Quarter 3 ... + CChartObjectHLine *q3Line; + q3Line = new CChartObjectHLine(); + isCreated = q3Line.Create( + chartID, + prefix + "_Q3", + subWindow, + quarter3 // + ); + if (isCreated) + { + // + q3Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q3Line); + } + } + } + + // +}; + +////////////////////////////////////////////////////// + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +///////////////////////////////////////////////////////////// + +/** + * Check an XOBFVG instance has Required Conditions ... + * + * @param zone: XOBFVG instance ... + * @param state: XPOIState instance ... + * @param conditions: X121Conditions instance ... + * + * @return ( bool ) + */ +bool DetectInsideSelectedZoneConditions( + bool &isReversal, + XOBFVG &zone, + XPOIState &state, + X121Conditions &conditions, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + XOHCL bar; + result = bar.Init( + state.symbol, + state.period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + result = + zone.IsValid() && + state.IsValid() && + state.HasChild(); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + bool isBullish = zone.IsBullish(); + bool isBearish = zone.IsBearish(); + + // + double points = GetPoints(bar.symbol); + + // + double bullishScore = 0; + double bearishScore = 0; + double scoreMultiplier = 1.5; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + + // // + // bool isLowerBreaked = + // // + // conditions.isSarBearish && + // conditions.isCheBearish && + // bar.high < zone.ob.Lower() && + // bearishScore > bullishScore && + // conditions.isX3MaBearishState && + // conditions.isVWapBearishState && + // conditions.isX3MaBearishOrdered && + // conditions.isVWapBearishOrdered && + // bar.low < conditions.atrLowerBuffer[1] && + // conditions.atrLowerBuffer[1] < zone.ob.Lower() + // // + // ; + + // // + // bool isUpperBreaked = + // // + // conditions.isSarBullish && + // conditions.isCheBullish && + // bar.low > zone.ob.Upper() && + // bullishScore > bearishScore && + // conditions.isX3MaBullishState && + // conditions.isVWapBullishState && + // conditions.isX3MaBullishOrdered && + // conditions.isVWapBullishOrdered && + // bar.high > conditions.atrUpperBuffer[1] && + // conditions.atrUpperBuffer[1] > zone.ob.Upper() + // // + // ; + + // // + // bool isPeakEqualsToUpper = + // MathAbs(conditions.peaksBuffer[0] - zone.ob.Upper()) > points * 1; + + // // + // bool isValeEqualsToLower = + // MathAbs(conditions.valesBuffer[0] - zone.ob.Lower()) > points * 1; + + // + // bool isDirectionalBullishPassed = + // // + // isBullish && + // isUpperBreaked + // // ( + + // // || + // // isValeEqualsToLower) + // // + // ; + + // + // bool isDirectionalBearishPassed = + // // + // isBearish && + // isLowerBreaked + // // || + // // isPeakEqualsToUpper) + // // + // ; + + // + // bool isDirectionalPassed = + // isDirectionalBullishPassed || + // isDirectionalBearishPassed; + + // // + // bool isReversalBullishPassed = + // // + // // isBullish && + // // isLowerBreaked + // // ( || + // // isPeakEqualsToUpper) + // // + // ; + + // // + // bool isReversalBearishPassed = + // // + // // isBearish && + // // isUpperBreaked + // // || + // // isValeEqualsToLower) + // // + // ; + + // + // bool isReversalPassed = isReversalBullishPassed || + // isReversalBearishPassed; + + // + // result = isReversalPassed || + // isDirectionalPassed; + + // + result = false; + + // + if (result) + { + // isReversal = isReversalPassed; + } + + // + bar.Clean(); + return result; +} + +bool DetectBreakedSelectedZoneConditions( + bool &isReversal, + XOBFVG &zone, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState, + X121Conditions &conditions // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + result = + // + zone.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + ttfState.IsValid() && + mtfState.HasChild() && + stfState.HasChild() && + ttfState.HasChild() + // + ; + if (!result) + { + return result; + } + + // + XBoxZone iBox; + result = ToBox( + iBox, + zone.ob // + ); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + bool isBearish = IsBearish(iDir); + + // + // X3Ma ... + + // + double x3maFast = conditions.x3maFastBuffer[0]; + double x3maMid = conditions.x3maMidBuffer[0]; + double x3maSlow = conditions.x3maSlowBuffer[0]; + + // + bool isX3mInside = + // + (x3maFast < iBox.upper && + x3maMid < iBox.upper && + x3maSlow < iBox.upper) + // + && + // + (x3maFast > iBox.lower && + x3maMid > iBox.lower && + x3maSlow > iBox.lower) + // + ; + + // + bool isBullishConditions = + isBullish && + isX3mInside; + + // + bool isBearishConditions = + isBearish && + isX3mInside; + + // + result = isBullishConditions || + isBearishConditions; + + // + return result; +} + +/** + * Detect SL Candidates Based on Selected Zone for Specified type of Directions ... + * + * @param sls: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingZone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * @param maxAllowedSLDistanceInPoint: doube max Allowe SL distance ... + * + * @return ( bool ) + */ +bool DetectSelectedZoneSLCandidates( + double &sls[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + X121SMCStrategyXWZWorkingZone &workingZone, + X121Conditions &conditions, + int barIndex = 0, + double maxAllowedSLDistanceInPoint = 300 // +) +{ + // + bool result = false; + + // + Clean(sls); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + double pivot = + isBullish + ? selectedZone.ob.Lower() + : selectedZone.ob.Upper(); + double points = GetPoints(workingZone.symbol); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + + // // + // double pvSL = isBullish + // ? conditions.valesBuffer[0] + // : conditions.peaksBuffer[1]; + + // // + // Add( + // pvSL, + // sls // + // ); + + // + // Based On Passed Bars ... + // XOHCL passedBar; + // bool isPassed = false; + // bool isBodyState = false; + // ENUM_X_DIRECTION passedDir = selectedZone.GetDirection(); + + // // + // // Started Bar ... + // isPassed = selectedZone.ob.IsStarted( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Activation Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Worked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Breaked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // + // Based On Consolidation Zones ... + // has = workingZone.HasConsolidationZones(); + // if (has) + // { + // // + // XConsolidationZone tmpZones[]; + // Copy( + // workingZone.consolidationZones, + // tmpZones // + // ); + // XConsolidationZone selectedConsolidationZone; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetYoungest(tmpZones); + // if (!IsValidIndex(idx)) + // { + // break; + // } + + // // + // XConsolidationZone iZone = tmpZones[idx]; + + // // + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // has = + // !selectedConsolidationZone.IsValid() + // ? isBullish + // ? cBar.low < iZone.upper + // : cBar.high < iZone.lower + // : isBullish + // ? selectedConsolidationZone.lower < iZone.lower + // : selectedConsolidationZone.upper > iZone.upper; + // if (has) + // { + // // + // selectedConsolidationZone = iZone; + // iZone.Clean(); + // break; + // } + + // // + // iZone.Clean(); + // } + + // // + // Clean(tmpZones); + // has = selectedConsolidationZone.IsValid(); + // if (has) + // { + // // + // double iSL = + // isBullish + // ? selectedConsolidationZone.lower + // : selectedConsolidationZone.upper; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + // } + + // + // Based On Supply and Demand Zones ... + + // + // Demand Zones ... + // has = workingZone.HasDemandZones(); + // if (has) + // { + // // + // XCDemandZone *tmpZones[]; + // Copy( + // workingZone.demandZones, + // tmpZones // + // ); + // XCDemandZone *selectedDemand = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetLowest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCDemandZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // isBullish + // ? IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedDemand == NULL + // ? true + // : isBullish + // ? selectedDemand.Lower() < iZone.Lower() + // : selectedDemand.Upper() > iZone.Upper(); + // if (!has) + // { + // continue; + // } + + // // + // selectedDemand = iZone; + // } + + // // + // has = selectedDemand != NULL; + // if (has) + // { + // // + // double iSL = + // isBullish + // ? selectedDemand.Lower() + // : selectedDemand.Upper(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedDemand); + // } + + // + // Support Zones ... + // has = workingZone.HasSupportZones(); + // if (has) + // { + // // + // XCSupportZone *tmpZones[]; + // Copy( + // workingZone.supportZones, + // tmpZones // + // ); + // XCSupportZone *selectedSupport = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetLowest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCSupportZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // isBullish + // ? IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedSupport == NULL + // ? true + // : isBullish + // ? selectedSupport.Lower() < iZone.Lower() + // : selectedSupport.Upper() > iZone.Upper(); + // if (!has) + // { + // continue; + // } + + // // + // selectedSupport = iZone; + + // // + // } + + // // + // has = selectedSupport != NULL; + // if (has) + // { + // // + // double iSL = isBullish + // ? selectedSupport.Lower() + // : selectedSupport.Upper(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedSupport); + // } + + // + // Supply Zones ... + // has = workingZone.HasSupplyZones(); + // if (has) + // { + // // + // XCSupplyZone *tmpZones[]; + // Copy( + // workingZone.supplyZones, + // tmpZones // + // ); + // XCSupplyZone *selectedSupply = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetHighest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCSupplyZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // !isBullish + // ? IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedSupply == NULL + // ? true + // : !isBullish + // ? selectedSupply.Upper() > iZone.Upper() + // : selectedSupply.Lower() < iZone.Lower(); + // if (!has) + // { + // continue; + // } + + // // + // selectedSupply = iZone; + + // // + // } + + // // + // has = selectedSupply != NULL; + // if (has) + // { + // // + // double iSL = + // !isBullish + // ? selectedSupply.Upper() + // : selectedSupply.Lower(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedSupply); + // } + + // + // Resistance Zones ... + // has = workingZone.HasDemandZones(); + // if (has) + // { + // // + // XCResistanceZone *tmpZones[]; + // Copy( + // workingZone.resistanceZones, + // tmpZones // + // ); + // XCResistanceZone *selectedResistance = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetHighest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCResistanceZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // !isBullish + // ? IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedResistance == NULL + // ? true + // : !isBullish + // ? selectedResistance.Upper() < iZone.Upper() + // : selectedResistance.Lower() > iZone.Lower(); + // if (!has) + // { + // continue; + // } + + // // + // selectedResistance = iZone; + + // // + // } + + // // + // has = selectedResistance != NULL; + // if (has) + // { + // // + // double iSL = + // !isBullish + // ? selectedResistance.Upper() + // : selectedResistance.Lower(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedResistance); + // } + + // + // Cleanp Resources ... + + // + cBar.Clean(); + // passedBar.Clean(); + result = HasChild(sls); + + // + return result; +} + +///////////////////////////////////////////////////////////////////////// + +// +// Support Zones ... +// has = HasSupportZones(); +// if (has) +// { +// // +// int removeIDXs[]; +// count = CountSupportZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCSupportZone *iZone = supportZones[i]; +// ENUM_X_DIRECTION iDir = X_DIRECTION_BULLISH; + +// // +// XBoxZone iBox; +// bool hasBox = ToBox( +// iBox, +// iZone // +// ); +// if (!hasBox) +// { +// // +// iBox.Clean(); +// continue; +// } + +// // +// XOHCL passedBar; +// bool isBodyIn = false; +// bool isBodyOut = false; + +// // +// // Check Activation ... +// bool isActivated = iZone.IsActivated( +// iDir, +// passedBar, +// isBodyIn, +// true, +// period // +// ); +// if (isActivated) +// { +// // +// // AddRef( +// // iBox, +// // insideBoxes // +// // ); + +// // +// Add( +// i, +// removeIDXs // +// ); + +// // +// iBox.Clean(); +// passedBar.Clean(); +// continue; +// } + +// // +// // Checking Breaked ... +// bool isBreaked = iZone.IsBreaked( +// iDir, +// passedBar, +// isBodyOut, +// false, +// true, +// period // +// ); +// if (isBreaked) +// { +// // // +// // AddRef( +// // iBox, +// // breakedBoxes // +// // ); + +// // +// Add( +// i, +// removeIDXs // +// ); + +// // +// iBox.Clean(); +// passedBar.Clean(); +// continue; +// } + +// // +// passedBar.Clean(); +// } + +// // +// count = ArraySize(removeIDXs); +// has = IsValidSize(count); +// if (has) +// { +// // +// CleanupArray( +// removeIDXs, +// supportZones // +// ); +// } + +// // +// Clean(removeIDXs); +// } + +// +// Resistance Zones ... +// has = HasResistanceZones(); +// if (has) +// { +// // +// int removeIDXs[]; +// count = CountResistanceZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCResistanceZone *iZone = resistanceZones[i]; +// ENUM_X_DIRECTION iDir = X_DIRECTION_BEARISH; + +// // +// XBoxZone iBox; +// bool hasBox = ToBox( +// iBox, +// iZone // +// ); +// if (!hasBox) +// { +// // +// iBox.Clean(); +// continue; +// } + +// // +// XOHCL passedBar; +// bool isBodyIn = false; +// bool isBodyOut = false; + +// // +// // Check Activation ... +// bool isActivated = iZone.IsActivated( +// iDir, +// passedBar, +// isBodyIn, +// true, +// period // +// ); +// if (isActivated) +// { +// // +// // AddRef( +// // iBox, +// // insideBoxes // +// // ); + +// // +// Add( +// i, +// removeIDXs // +// ); + +// // +// iBox.Clean(); +// passedBar.Clean(); +// continue; +// } + +// // +// // Checking Breaked ... +// bool isBreaked = iZone.IsBreaked( +// iDir, +// passedBar, +// isBodyOut, +// false, +// true, +// period // +// ); +// if (isBreaked) +// { +// // // +// // AddRef( +// // iBox, +// // breakedBoxes // +// // ); + +// // +// Add( +// i, +// removeIDXs // +// ); + +// // +// iBox.Clean(); +// passedBar.Clean(); +// continue; +// } + +// // +// passedBar.Clean(); +// } + +// // +// count = ArraySize(removeIDXs); +// has = IsValidSize(count); +// if (has) +// { +// // +// CleanupArray( +// removeIDXs, +// resistanceZones // +// ); +// } + +// // +// Clean(removeIDXs); +// } + +//////////////////////////////////////////////////////// + +// +// Waiting Zone Detection ... +// XPOIState iState = mtfState; + +// +// Detect Waiting Zones ... + +// // +// // Using Order Blocks ... +// if (mUseOrderBlocks) +// { +// // +// has = iState.HasOrderBlocks(); +// if (has) +// { +// // +// XCOrderBlock *obs[]; +// count = iState.FilterOrderBlocks( +// obs, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); + +// // +// has = IsValidSize(count); +// if (has) +// { +// // +// ToBox( +// obs, +// waitingBoxes // +// ); +// } + +// // +// Clean(obs); +// } +// } + +// // +// // Using Fair Value Gaps ... +// if (mUseFairValueGaps) +// { +// // +// has = iState.HasFairValueGaps(); +// if (has) +// { +// // +// XBoxZone boxes[]; +// XCFVG *fvgs[]; +// count = iState.FilterFairValueGaps( +// fvgs, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); + +// // +// has = IsValidSize(count); +// if (has) +// { +// // +// count = ToBox( +// fvgs, +// boxes // +// ); + +// // +// for (int i = 0; i < count; i++) +// { +// // +// XBoxZone iBox = boxes[i]; + +// // +// int idx = FindIndex( +// iBox, +// waitingBoxes // +// ); +// has = !IsValidIndex(idx); +// if (has) +// { +// // +// AddRef( +// iBox, +// waitingBoxes // +// ); +// } + +// // +// iBox.Clean(); +// } +// } + +// // +// Clean(fvgs); +// Clean(boxes); +// } +// } + +// +// Cleaning State ... +// iState.Clean(); + +/////////////////////////////////////////////////////////////////////////// + +// +// Waiting Box Detected ... +bool hasWaitingBoxes = hasWorkingZone && + workingZone.HasWaitingBoxes(); +if (hasWaitingBoxes) +{ + // + XOHCL zBar; + XOHCL cBar; + XOHCL pBar; + int count = 0; + int idx = -1; + bool has = false; + + // + bool isInited = zBar.Init( + symbol, + period, + zIndex // + ); + isInited = + isInited && + zBar.GetPreviousBar(cBar); + isInited = + isInited && + cBar.GetPreviousBar(pBar); + + // + count = workingZone.CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = workingZone.waitingBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + // Check Price Rejection ... + + // + bool hasBullishFiboPressure = + decisionCycleHelper + .mBarAnalyser + .HasFiboPressure( + cBar, + X_DIRECTION_BULLISH, + X_FIBO_LEVEL_382 // + ); + + // + bool hasBearishFiboPressure = + decisionCycleHelper + .mBarAnalyser + .HasFiboPressure( + cBar, + X_DIRECTION_BEARISH, + X_FIBO_LEVEL_382 // + ); + + // + // Bullish Rejection ... + bool isBullishRejected = + // + isInited && + isBullish && + cBar.low < pBar.low && + zBar.low > iBox.upper && + cBar.low <= iBox.upper && + zBar.open > iBox.upper && + hasBullishFiboPressure && + cBar.GetLowShadow() > pBar.GetLowShadow() + // + ; + + // + // Bearish Rejection ... + bool isBearishhRejected = + // + isInited && + !isBullish && + cBar.high > pBar.high && + zBar.open < iBox.lower && + zBar.high < iBox.lower && + hasBearishFiboPressure && + cBar.high >= iBox.lower && + cBar.GetHighShadow() > pBar.GetHighShadow() + // + ; + + // + has = isBullishRejected || + isBearishhRejected; + if (has) + { + // + idx = i; + signalBox = iBox; + hasSignalBox = has; + signalBox.to = cTime; + signalBoxDir = iBox.dir; + isSignalBoxReversal = false; + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE; + } + + // + iBox.Clean(); + } + + // + // Remove Signal Box from Waiting Boxes of + // Working Zone ... + if (hasSignalBox) + { + // + if (IsValidIndex(idx)) + { + // + ArrayRemove( + workingZone.waitingBoxes, + idx, + 1 // + ); + } + } + + // + // Ignore Zone's Signals ... + hasSignalBox = false; + + // + // Cleanup Resources ... + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); +} + +// +// Check Conditions if Has Inside Boxes ... +bool hasInsideBoxes = hasWorkingZone && + workingZone.HasInsideBoxes(); +if (hasInsideBoxes) +{ +} + +// +// Check Conditions if has Breaked Boxes ... +bool hasBreakedBoxes = hasWorkingZone && + workingZone.HasBreakedBoxes(); +if (hasBreakedBoxes) +{ +} + +// +// Checking Other Conditions ... +if (!hasSignalBox) +{ + // + // Senari A ... + // hasSignalBox = hasWorkingZone && + // workingZone.DetectSenarioASignalBox( + // signalBox, + // signalBoxDir, + // decisionXConditions, + // analyseXConditions, + // decisionCycleHelper, + // drawer, + // zIndex // + // ); + // if (hasSignalBox) + // { + // // + // signalBox.to = cTime; + // isSignalBoxReversal = false; + // provider = X121SMC_XWZ_PROVIDER_PV_ZONE; + // } + + // // + // // Validating Signal Box if Exists ... + // if (hasSignalBox) + // { + // // + // // Validate Signal Boxes using Inside Box ... + // if (hasInsideBoxes) + // { + // // + // int idx = -1; + // bool has = false; + + // // + // idx = + // IsBullish(signalBoxDir) + // ? GetLowest(workingZone.insideBoxes) + // : GetHighest(workingZone.insideBoxes); + // has = IsValidIndex(idx); + // if (has) + // { + // // + // hasSignalBox = + // signalBoxDir == workingZone.insideBoxes[idx].dir; + // } + // } + + // // + // // Validate Signal Box Using Overal Trend ... + // if (hasWorkingZoneOveralDirection) + // { + // // + // hasSignalBox = + // signalBoxDir == wzOveralDir; + // } + // } +} + +////////////////////////////////////////////////////////////////////////////////// + +// +// +// + +// +// Supply Zones ... +has = HasSupplyZones(); +if (has) +{ + // + int removeIDXs[]; + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = supplyZones[i]; + ENUM_X_DIRECTION iDir = X_DIRECTION_BEARISH; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + XOHCL passedBar; + bool isBodyIn = false; + bool isBodyOut = false; + + // + // Check Activation ... + bool isActivated = iZone.IsActivated( + iDir, + passedBar, + isBodyIn, + true, + period // + ); + if (isActivated) + { + // + // AddRef( + // iBox, + // insideBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + // Checking Breaked ... + bool isBreaked = iZone.IsBreaked( + iDir, + passedBar, + isBodyOut, + false, + true, + period // + ); + if (isBreaked) + { + // // + // AddRef( + // iBox, + // breakedBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + passedBar.Clean(); + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + supplyZones // + ); + } + + // + Clean(removeIDXs); +} + +// +// Demand Zones ... +has = HasDemandZones(); +if (has) +{ + // + int removeIDXs[]; + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = demandZones[i]; + ENUM_X_DIRECTION iDir = X_DIRECTION_BULLISH; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + XOHCL passedBar; + bool isBodyIn = false; + bool isBodyOut = false; + + // + // Check Activation ... + bool isActivated = iZone.IsActivated( + iDir, + passedBar, + isBodyIn, + true, + period // + ); + if (isActivated) + { + // + // AddRef( + // iBox, + // insideBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + // Checking Breaked ... + bool isBreaked = iZone.IsBreaked( + iDir, + passedBar, + isBodyOut, + false, + true, + period // + ); + if (isBreaked) + { + // // + // AddRef( + // iBox, + // breakedBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + passedBar.Clean(); + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + demandZones // + ); + } + + // + Clean(removeIDXs); +} + +// +// Update Boxes ... + +// +// Waiting Boxes ... +has = HasWaitingBoxes(); +if (has) +{ + // + int removeIDXs[]; + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = waitingBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isInside = + // + zBar.low < iBox.upper && + zBar.low > iBox.lower + // + ; + if (isInside) + { + // + AddRef( + iBox, + insideBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + + // + bool isBreakedUpper = + // + cBar.low < iBox.upper && + cBar.low > iBox.lower && + zBar.low > iBox.upper + // + ; + + // + bool isBreakedLower = + // + cBar.high > iBox.lower && + cBar.high < iBox.upper && + zBar.high < iBox.lower + // + ; + + // + bool isBreaked = + (isBullish && + isBreakedLower) || + (!isBullish && + isBreakedUpper); + + // + if (isBreaked) + { + // + AddRef( + iBox, + breakedBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + waitingBoxes // + ); + } + + // + Clean(removeIDXs); +} + +// +// Inside Boxes ... +has = HasInsideBoxes(); +if (has) +{ + // + int removeIDXs[]; + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = insideBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isBreakedUpper = + // + cBar.low < iBox.upper && + cBar.low > iBox.lower && + zBar.low > iBox.upper + // + ; + + // + bool isBreakedLower = + // + cBar.high > iBox.lower && + cBar.high < iBox.upper && + zBar.high < iBox.lower + // + ; + + // + bool isBreaked = + (isBullish && + isBreakedLower) || + (!isBullish && + isBreakedUpper); + + // + if (isBreaked) + { + // + AddRef( + iBox, + breakedBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + insideBoxes // + ); + } + + // + Clean(removeIDXs); +} + +// +has = HasBreakedBoxes(); +if (has) +{ + // + int removeIDXs[]; + count = CountBreakedBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = breakedBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isInside = false; + + // + if (isInside) + { + // + AddRef( + iBox, + breakedInsideBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + breakedBoxes // + ); + } + + // + Clean(removeIDXs); +} + +// +// Update Waiting Boxes ... + +// +XPOIState iState = mtfState; + +// +// Use Order Blocks ... +if (mUseOrderBlocks) +{ + // + has = iState.HasOrderBlocks(); + if (has) + { + // + XCOrderBlock *obs[]; + count = iState.FilterOrderBlocks( + obs, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + + // + has = IsValidSize(count); + if (has) + { + // + // Try to Add new OBs into Waiting Zones ... + // if it's not exists ... + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + obs[i] // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Waiting Boxes ... + idx = FindIndex( + iBox, + waitingBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Inside Boxes ... + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Breaked Boxes ... + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + AddRef( + iBox, + waitingBoxes // + ); + } + } + + // + Clean(obs); + } +} + +// +// Use Fair Value Gaps ... +if (mUseFairValueGaps) +{ + // + has = iState.HasFairValueGaps(); + if (has) + { + // + XCFVG *fvgs[]; + count = iState.FilterFairValueGaps( + fvgs, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + + // + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + fvgs[i] // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Waiting Boxes ... + idx = FindIndex( + iBox, + waitingBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Inside Boxes ... + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Breaked Boxes ... + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + AddRef( + iBox, + waitingBoxes // + ); + + // + iBox.Clean(); + } + } + + // + Clean(fvgs); + } +} + +// +iState.Clean(); + +///////////////////////////////////////////////////////////////////////////// + +// +// Update Working Zone ... +// workingZone.Update( +// zIndex, +// visionState, +// consolidationState, +// analyseState, +// decisionState // +// ); + +////////////////////////////////////////////////////////////////////////////////// + +// +// +// + +// +// Supply Zones ... +if (drawSupplyZones) +{ + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } +} + +// +// Demand Zones ... +if (drawDemandZones) +{ + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } +} + +// +// Support Zones ... +if (drawSupportZones) +{ + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = drawer.CreateSupportZone( + supportZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } +} + +// +// Resistance Zones ... +if (drawResistanceZones) +{ + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = drawer.CreateResistanceZone( + resistanceZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } +} + +// +// +// + +// +// Waiting Boxes ... +if (drawWaitingBoxes) +{ + // + has = HasWaitingBoxes(); + if (has) + { + // + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = waitingBoxes[i]; + + // + XCBoxObject *iObj; + bool isCreated = drawer.DrawBox( + iBox, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + + // + iBox.Clean(); + } + } +} + +// +// Inside Boxes ... +if (drawInsideBoxes) +{ + // + has = HasInsideBoxes(); + if (has) + { + } +} + +// +// Breaked Boxes ... +if (drawBreakedBoxes) +{ + // + has = HasBreakedBoxes(); + if (has) + { + // + } +} + +// +// Breaked Inside Boxes ... +if (drawBreakedInsideBoxes) +{ + // + has = HasBreakedInsideBoxes(); + if (has) + { + // + count = CountBreakedInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = breakedInsideBoxes[i]; + XCBoxObject *iObj; + has = drawer.DrawBox( + iBox, + iObj // + ); + if (has) + { + // + iObj.BoxWidth(1); + mBreakedInsideZoneObjects.Add(iObj); + } + } + } +} + +////////////////////////////////////////////////////////////////////////////////// + +// +XCSupplyZone *supplyZone; +XCDemandZone *demandZone; + +// +XCSupplyZone *supplyZones[]; +XCDemandZone *demandZones[]; + +// +XCSupportZone *supportZones[]; +XCResistanceZone *resistanceZones[]; + +// +XBoxZone insideBoxes[]; +XBoxZone breakedBoxes[]; +XBoxZone waitingBoxes[]; +XBoxZone breakedInsideBoxes[]; +XConsolidationZone consolidationZones[]; + +// +bool mUseSupDems; +bool mUseOrderBlocks; +bool mUseFairValueGaps; + +// +// +// + +// // +// // Supply Zones ... +// has = HasSupplyZones(); +// if (!has) +// { +// // +// count = mtfState.FilterSupplyZones( +// supplyZones, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); +// } + +// // +// // Demand Zones ... +// has = HasDemandZones(); +// if (!has) +// { +// // +// count = mtfState.FilterDemandZones( +// demandZones, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); +// } + +// +// Support Zones ... +// has = HasSupportZones(); +// if (!has) +// { +// // +// count = mtfState.FilterSupportZones( +// supportZones, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); +// } + +// +// Resistance Zones ... +// has = HasResistanceZones(); +// if (!has) +// { +// // +// count = mtfState.FilterResistanceZones( +// resistanceZones, +// period, +// XZONE_STATE_PASSED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_FAILED, +// false, +// XZONE_STATE_IGNORED, +// false // +// ); +// } + +// +// Update Exists Zones ... + +// +// Supply Zones ... +has = mtfState.HasSupplyZones(); +if (has) +{ + // + XCSupplyZone *zone; + idx = GetYoungest(mtfState.supplyZones); + has = IsValidIndex(idx); + if (has) + { + // + zone = mtfState.supplyZones[idx]; + has = IsSupplyExists(zone); + if (!has) + { + // + Add( + zone, + supplyZones // + ); + } + else + { + ZeroMemory(zone); + } + } +} + +// +// Demand Zones ... +has = mtfState.HasDemandZones(); +if (has) +{ + // + XCDemandZone *zone; + idx = GetYoungest(mtfState.demandZones); + has = IsValidIndex(idx); + if (has) + { + // + zone = mtfState.demandZones[idx]; + has = IsDemandExists(zone); + if (!has) + { + // + Add( + zone, + demandZones // + ); + } + else + { + ZeroMemory(zone); + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +// +bool IsExists(XBoxZone &box) +{ + // + bool result = false; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + bool has = false; + + // + // Checking Index Waiting Box ... + has = HasWaitingBoxes(); + if (has) + { + // + idx = FindIndex( + box, + waitingBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index Inside Boxes ... + has = HasInsideBoxes(); + if (has) + { + // + idx = FindIndex( + box, + insideBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index Breaked Boxes ... + has = HasBreakedBoxes(); + if (has) + { + // + idx = FindIndex( + box, + breakedBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index BreakedInside Boxes ... + has = HasBreakedInsideBoxes(); + if (has) + { + // + idx = FindIndex( + box, + breakedInsideBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + return result; +} + +// +bool IsSupplyExists(XCSupplyZone *zone) +{ + // + bool result = false; + + // + result = zone != NULL && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Converts Zone to Box ... + XBoxZone box; + result = ToBox( + box, + zone // + ); + if (!result) + { + // + box.Clean(); + return result; + } + + // + // Checking Index in SupplyZones ... + int idx = FindIndex( + zone, + supplyZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + box.Clean(); + return result; + } + + // + result = IsExists(box); + + // + box.Clean(); + + // + return result; +} + +// +bool IsDemandExists(XCDemandZone *zone) +{ + // + bool result = false; + + // + result = zone != NULL && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Converts Zone to Box ... + XBoxZone box; + result = ToBox( + box, + zone // + ); + if (!result) + { + // + box.Clean(); + return result; + } + + // + // Checking Index in SupplyZones ... + int idx = FindIndex( + zone, + demandZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + box.Clean(); + return result; + } + + // + result = IsExists(box); + + // + box.Clean(); + + // + return result; +} + +////////////////////////////////////////////////////////////////////////////// + +// +Clean(supplyZones); +Clean(demandZones); + +// +Clean(insideBoxes); +Clean(breakedBoxes); +Clean(waitingBoxes); + +// +Clean(supportZones); +Clean(resistanceZones); + +// +mUseSupDems = false; +mUseOrderBlocks = true; +mUseFairValueGaps = true; + +///////////////////////////////////////////////////////////////////////////// + +// +bool HasInsideBox( + XBoxZone &box // +) +{ + // + bool result = false; + + // + int index = -1; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int count = 0; + bool has = false; + + // + has = HasWaitingBoxes(); + if (has) + { + // + result = HasInsideBox( + index, + box, + waitingBoxes // + ); + } + + // + // Supply Zones ... + if (!result) + { + // + has = HasSupplyZones(); + if (has) + { + // + XBoxZone tmpBoxes[]; + count = ToBox( + supplyZones, + tmpBoxes // + ); + + // + has = IsValidSize(count); + if (has) + { + // + result = HasInsideBox( + index, + box, + tmpBoxes // + ); + } + + // + Clean(tmpBoxes); + } + } + + // + // Demand Zones ... + if (!result) + { + // + has = HasDemandZones(); + if (has) + { + // + XBoxZone tmpBoxes[]; + count = ToBox( + demandZones, + tmpBoxes // + ); + + // + has = IsValidSize(count); + if (has) + { + // + result = HasInsideBox( + index, + box, + tmpBoxes // + ); + } + + // + Clean(tmpBoxes); + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +// +bool DetectSenarioASignalBox( + XBoxZone &signalBox, + ENUM_X_DIRECTION &signalDir, + X121Conditions &decisionXConditions, + X121Conditions &analyseXConditions, + XC121SMCCycleHelper *decisionCycleHelper, + XCPOIDrawer *drawer = NULL, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + signalBox.Clean(); + signalDir = X_DIRECTION_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = decisionCycleHelper != NULL; + if (!result) + { + return result; + } + + // + // Decision ... + double decisionBullishScore = 0; + double decisionBearishScore = 0; + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + double analyseBullishScore = 0; + double analyseBearishScore = 0; + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // Score Conditions ... + double scoreMultiplier = 3; + bool isBullishScorePassed = + // + analyseBullishScore > (analyseBearishScore * scoreMultiplier) && + decisionBullishScore > (decisionBearishScore * scoreMultiplier) + // + ; + bool isBearishScorePassed = + // + analyseBearishScore > (analyseBullishScore * scoreMultiplier) && + decisionBearishScore > (decisionBullishScore * scoreMultiplier) + // + ; + + // + // Checking Other Conditions + + // + bool isCommonBullish = + // + decisionXConditions.isSarBullish && + decisionXConditions.isStrBullish && + decisionXConditions.isCheBullish && + decisionXConditions.isSMHKBullish && + decisionXConditions.isRawHKBullish && + decisionXConditions.isRawHKClosedOverSMHK + // + ; + + // + bool isCommonBearish = + // + decisionXConditions.isSarBearish && + decisionXConditions.isStrBearish && + decisionXConditions.isCheBearish && + decisionXConditions.isSMHKBearish && + decisionXConditions.isRawHKBearish && + decisionXConditions.isRawHKClosedUnderSMHK + // + ; + + // + // X3Ma ... + + // + // X3Ma Bullish ... + bool isX3MaBullish = + // + decisionXConditions.isX3MaBullishState && + decisionXConditions.isX3MaSwitchedToBullishOrdered && + decisionXConditions.x3maMidBuffer[1] > decisionXConditions.x3maSlowBuffer[1] + // + ; + + // + // X3Ma Bearish ... + bool isX3MaBearish = + // + decisionXConditions.isX3MaBearishState && + decisionXConditions.isX3MaSwitchedToBearishOrdered && + decisionXConditions.x3maMidBuffer[1] < decisionXConditions.x3maSlowBuffer[1] + // + ; + + // + bool isX3MaHasCondition = + (isX3MaBullish && + isCommonBullish && + isBullishScorePassed) || + (isX3MaBearish && + isCommonBearish && + isBearishScorePassed); + + // + // VWap ... + + // + // VWap Bullish ... + bool isVWapBullish = + // + decisionXConditions.isVWapBullishState && + decisionXConditions.isVWapSwitchedToBullishOrdered && + decisionXConditions.vwapMidBuffer[1] > decisionXConditions.vwapSlowBuffer[1] + // + ; + + // + // VWap Bearish ... + bool isVWapBearish = + // + decisionXConditions.isVWapBearishState && + decisionXConditions.isVWapSwitchedToBearishOrdered && + decisionXConditions.vwapMidBuffer[1] < decisionXConditions.vwapSlowBuffer[1] + // + ; + + // + bool isVWapHasCondition = + (isVWapBullish && + isBullishScorePassed) || + (isVWapBearish && + isBearishScorePassed); + + // + // Senario .... + // - a vale Under X3MA Slow when X3MA Bullish Ordered ... + + // + bool isX3MASenarioBBullish = + // + decisionXConditions.isX3MaBullishOrdered && + decisionXConditions.valesBuffer[1] < decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.valesBuffer[2] >= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBullish) + { + } + + // + bool isX3MASenarioBBearish = + // + decisionXConditions.isX3MaBearishOrdered && + decisionXConditions.peaksBuffer[1] > decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.peaksBuffer[2] <= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBearish) + { + } + + // + // Checking Other Conditions XWZ Reject on EMA 20 ... + + // + // Check Has Conditions ... + bool hasXConditions = + (isX3MaHasCondition || + isVWapHasCondition); + + // + result = hasXConditions; + if (!result) + { + return result; + } + + // + if (isX3MaHasCondition) + { + // + signalDir = + isX3MaBullish + ? X_DIRECTION_BULLISH + : isX3MaBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + if (isVWapHasCondition) + { + // + signalDir = + isVWapBullish + ? X_DIRECTION_BULLISH + : isVWapBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Creating SignalBox ... + + // + // Detect Box based on PV ... + bool hasSignalBox = decisionCycleHelper.GeneratePVBox( + signalBox, + barIndex // + ); + + // + result = + hasSignalBox && + signalDir == signalBox.dir; + + // + if (result) + { + // + XCBoxObject *iObj; + bool isCreated = drawer.DrawBox( + signalBox, + iObj // + ); + if (isCreated) + { + // + iObj.BoxWidth(1); + iObj.BoxColor(clrYellow); + iObj.BoxStyle(STYLE_SOLID); + } + + // + Print("Senario A ..."); + } + + // + return result; +} + +// +bool DetetctSenarioBSignalBox( + XBoxZone &signalBox, + ENUM_X_DIRECTION &signalDir, + X121Conditions &decisionXConditions, + X121Conditions &analyseXConditions, + XC121SMCCycleHelper *decisionCycleHelper, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + signalBox.Clean(); + signalDir = X_DIRECTION_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = decisionCycleHelper != NULL; + if (!result) + { + return result; + } + + // + // Decision ... + double decisionBullishScore = 0; + double decisionBearishScore = 0; + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + double analyseBullishScore = 0; + double analyseBearishScore = 0; + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // Score Conditions ... + double scoreMultiplier = 3; + bool isBullishScorePassed = + // + analyseBullishScore > (analyseBearishScore * scoreMultiplier) && + decisionBullishScore > (decisionBearishScore * scoreMultiplier) + // + ; + bool isBearishScorePassed = + // + analyseBearishScore > (analyseBullishScore * scoreMultiplier) && + decisionBearishScore > (decisionBullishScore * scoreMultiplier) + // + ; + + // + // Senario .... + // - a vale Under X3MA Slow when X3MA Bullish Ordered ... + + // + bool isX3MASenarioBBullish = + // + decisionXConditions.isX3MaBullishOrdered && + decisionXConditions.valesBuffer[1] < decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.valesBuffer[2] >= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBullish) + { + } + + // + bool isX3MASenarioBBearish = + // + decisionXConditions.isX3MaBearishOrdered && + decisionXConditions.peaksBuffer[1] > decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.peaksBuffer[2] <= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBearish) + { + } + + // + return result; +} + +// +bool HasSupplyZones() +{ + return HasChild(supplyZones); +} + +// +int CountSupplyZones() +{ + return ArraySize(supplyZones); +} + +// +bool HasDemandZones() +{ + return HasChild(demandZones); +} + +// +int CountDemandZones() +{ + return ArraySize(demandZones); +} + +// +bool HasSupportZones() +{ + return HasChild(supportZones); +} + +// +int CountSupportZones() +{ + return ArraySize(supportZones); +} + +// +bool HasResistanceZones() +{ + return HasChild(resistanceZones); +} + +// +int CountResistanceZones() +{ + return ArraySize(resistanceZones); +} + +// +bool HasConsolidationZones() +{ + return HasChild(consolidationZones); +} + +// +int CountConsolidationZones() +{ + return ArraySize(consolidationZones); +} + +// +bool HasWaitingBoxes() +{ + return HasChild(waitingBoxes); +} + +// +int CountWaitingBoxes() +{ + return ArraySize(waitingBoxes); +} + +// +bool HasInsideBoxes() +{ + return HasChild(insideBoxes); +} + +// +int CountInsideBoxes() +{ + return ArraySize(insideBoxes); +} + +// +bool HasBreakedBoxes() +{ + return HasChild(breakedBoxes); +} + +// +int CountBreakedBoxes() +{ + return ArraySize(breakedBoxes); +} + +// +bool HasBreakedInsideBoxes() +{ + return HasChild(breakedInsideBoxes); +} + +// +int CountBreakedInsideBoxes() +{ + return ArraySize(breakedInsideBoxes); +} + +/////////////////////////////////////////////////////////////////////////////////// + +// +has = ttfState.HasConsolidationZones(); +if (has) +{ + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); +} + +// +has = HasSupplyZones(); +if (has) +{ + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } +} + +// +has = HasDemandZones(); +if (has) +{ + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } +} + +// +has = HasSupportZones(); +if (has) +{ + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + supportZones[i].To(value); + } +} + +// +has = HasResistanceZones(); +if (has) +{ + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + resistanceZones[i].To(value); + } +} + +// +// +// + +// +has = HasWaitingBoxes(); +if (has) +{ + // + count = ArraySize(waitingBoxes); + for (int i = 0; i < count; i++) + { + waitingBoxes[i].to = value; + } +} + +// +has = HasInsideBoxes(); +if (has) +{ + // + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + insideBoxes[i].to = value; + } +} + +// +has = HasBreakedBoxes(); +if (has) +{ +} + +// +has = HasBreakedInsideBoxes(); +if (has) +{ + // + count = CountBreakedInsideBoxes(); + for (int i = 0; i < count; i++) + { + breakedInsideBoxes[i].to = value; + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +// +XBoxZone waitingBoxes[]; +has = workingZone.HasWaitingBoxes(); +if (has) +{ + // + Copy( + workingZone.waitingBoxes, + waitingBoxes // + ); + + // + while (HasChild(waitingBoxes)) + { + // + XBoxZone iBox; + idx = GetYoungest(waitingBoxes); + has = IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + iBox = waitingBoxes[idx]; + ArrayRemove( + waitingBoxes, + idx, + 1 // + ); + + // + bool hasInside = workingZone.HasInsideBox(iBox); + if (!hasInside) + { + continue; + } + + // + double iTarget = + IsBullish(signalBoxDir) + ? iBox.lower + : iBox.upper; + + // + Add( + iTarget, + targets // + ); + + // + iBox.Clean(); + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +// +void Update( + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState // +) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + has = + // + IsValid() && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() + // + ; + if (!has) + { + return; + } + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + zBar.Clean(); + return; + } + + // + XOHCL cBar; + has = zBar.GetPreviousBar(cBar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + + // + return; + } + + // + // Cleanup Resource ... + + // + zBar.Clean(); + cBar.Clean(); +} + +/////////////////////////////////////////////////////////////////////////////////// + +// +int ExtractOBFVGs( + XOBFVG &dest[], + XPOIState &obState, + XPOIState &fvgState, + // + ENUM_X_OBFVG_FVG_FILTERS filterFVGs = X_OBFVG_FVG_FILTER_INSIDE_OR, + ENUM_X_OBFVG_FVG_SELECTION selectFVG = X_OBFVG_FVG_SELECT_OLDEST, + // + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_IGNORED, + bool forceWorkedBodyOut = false // +) +{ + // + int result = 0; + + // + bool has = false; + + // + Clean(dest); + + // + has = obState.IsValid() && + fvgState.IsValid() && + obState.HasChild() && + fvgState.HasChild() && + selectFVG != X_OBFVG_FVG_SELECT_NONE && + filterFVGs != X_OBFVG_FVG_FILTER_NONE; + if (!has) + { + return result; + } + + // + XCOrderBlock *obs[]; + int obsCount = obState.FilterOrderBlocks( + obs, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + has = IsValidSize(obsCount); + if (!has) + { + return result; + } + + // + XCFVG *fvgs[]; + int fvgsCount = fvgState.FilterFairValueGaps( + fvgs, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + has = IsValidSize(fvgsCount); + if (!has) + { + return result; + } + + // + for (int i = 0; i < obsCount; i++) + { + // + XCOrderBlock *iOB = obs[i]; + XCFVG *iFVG = NULL; + + // + ENUM_X_DIRECTION iOBDir = iOB.GetDirection(); + bool isIOBBullish = IsBullish(iOBDir); + + // + XCFVG *iFVGs[]; + for (int j = 0; j < fvgsCount; j++) + { + // + XCFVG *jFVG = fvgs[j]; + ENUM_X_DIRECTION jFVGDir = jFVG.GetDirection(); + + // + bool isSameDir = iOBDir == jFVGDir; + bool isFromPassed = jFVG.From() >= iOB.From(); + bool isInsideOr = IsInsideOrDiff( + jFVG, + iOB // + ); + bool isAbove = IsAboveDiff( + jFVG, + iOB, + true // + ); + bool isBelow = IsBelowDiff( + jFVG, + iOB, + true // + ); + + // + bool isFilterPassed = + filterFVGs == X_OBFVG_FVG_FILTER_ABOVE_BELOW + ? isIOBBullish + ? isAbove + : isBelow + : filterFVGs == X_OBFVG_FVG_FILTER_INSIDE_OR + ? isInsideOr + : false; + + // + has = + isSameDir && + isFromPassed && + isFilterPassed; + if (has) + { + // + Add( + jFVG, + iFVGs // + ); + } + } + has = HasChild(iFVGs); + if (!has) + { + continue; + } + + // + int idx = -1; + idx = selectFVG == X_OBFVG_FVG_SELECT_OLDEST + ? GetOldest(iFVGs) + : selectFVG == X_OBFVG_FVG_SELECT_YOUNGEST + ? GetYoungest(iFVGs) + : selectFVG == X_OBFVG_FVG_SELECT_HIGHEST_LOWEST + ? isIOBBullish + ? GetHighest(iFVGs) + : GetLowest(iFVGs) + : selectFVG == X_OBFVG_FVG_SELECT_LOWEST_HIGHEST + ? isIOBBullish + ? GetLowest(iFVGs) + : GetHighest(iFVGs) + : selectFVG == X_OBFVG_FVG_SELECT_LOWEST + ? GetLowest(iFVGs) + : selectFVG == X_OBFVG_FVG_SELECT_HIGHEST + ? GetHighest(iFVGs) + : -1; + + // + has = IsValidIndex(idx); + if (!has) + { + continue; + } + + // + iFVG = iFVGs[idx]; + Clean(iFVGs); + + // + XOBFVG iOBFVG; + iOBFVG.ob = iOB; + iOBFVG.fvg = iFVG; + + // + has = iOBFVG.IsValid(); + if (!has) + { + // + iOBFVG.Clean(); + continue; + } + + // + AddRef( + iOBFVG, + dest // + ); + + // + iOBFVG.Clean(); + } + + // + result = ArraySize(dest); + + // + return result; +} + +/////////////////////////////////////////////////////////////////////////////////// + +// // +// XCBaseObject *obObject; +// bool isCreated = drawer.CreateOrderBlock( +// obFVG.ob, +// obObject // +// ); + +// // +// count = obFVG.CountFVGs(); +// for (int i = 0; i < count; i++) +// { +// // +// XCBaseObject *fvgObject; +// isCreated = drawer.CreateFairValueGap( +// obFVG.fvgs[i], +// fvgObject // +// ); +// } + +/////////////////////////////////////////////////////////////////////////////////// + +// +// Detect OB FVG ... +// result = +// hasNewOrderBlock && +// hasNewFairValueGap && +// ob.GetDirection() == fvg.GetDirection(); +// if (result) +// { +// // +// obFVG.ob = ob; +// obFVG.AddFVG(fvg); + +// // +// has = obFVG.IsValid(); +// if (has) +// { +// // +// has = IsExists(obFVG); +// if (!has) +// { +// // +// // New Waiting Zone ... +// AddRef( +// obFVG, +// waitingZones // +// ); +// } +// else +// { +// // +// // Check Item Is not Exists ... +// idx = FindIndex( +// obFVG, +// waitingZones // +// ); +// has = !IsValidIndex(idx); +// if (!has) +// { +// // +// // Update Exists Waiting Zone ... +// waitingZones[idx].AddFVG(fvg); +// } +// } +// } +// } + +// // +// XCFVG *decisionFVG; +// bool hasNewDecisionFVG = +// Contains( +// X_BULLISH_FVG_DETECTED, +// provider +// .decisionPoiEvents // +// ) || +// Contains( +// X_BEARISH_FVG_DETECTED, +// provider +// .decisionPoiEvents // +// ); +// if (hasNewDecisionFVG) +// { +// // +// idx = GetYoungest(provider +// .decisionState +// .fairValueGaps // +// ); +// has = IsValidIndex(idx); +// if (has) +// { +// // +// decisionFVG = provider +// .decisionState +// .fairValueGaps[idx]; + +// // +// XCBaseObject *iObj; +// bool isCreated = drawer.CreateFairValueGap( +// decisionFVG, +// iObj // +// ); + +// // +// if (isCreated) +// { +// Print("New Fair Value Gap ..."); +// } +// } +// } + +// +// Detect SupDem FVG ... +// if (!result) +// { +// // +// result = hasNewFairValueGap && +// (hasNewSupply || +// hasNewDemand); +// if (result) +// { +// // +// // Converts Supply or Demand Zone to OrderBlock ... +// XOHCL bar; +// ob = new XCOrderBlock(); +// if (hasNewSupply) +// { +// // +// has = supply.FillBar(bar); +// if (has) +// { +// // +// has = ob.Init( +// bar, +// X_DIRECTION_BEARISH // +// ); +// if (has) +// { +// // +// ob.Upper(supply.Upper()); +// ob.Lower(supply.Lower()); +// } +// } +// } +// else if (hasNewDemand) +// { +// // +// has = demand.FillBar(bar); +// if (has) +// { +// // +// has = ob.Init( +// bar, +// X_DIRECTION_BULLISH // +// ); +// if (has) +// { +// // +// ob.Upper(demand.Upper()); +// ob.Lower(demand.Lower()); +// } +// } +// } + +// // +// obFVG.ob = ob; +// obFVG.AddFVG(fvg); + +// // +// has = obFVG.IsValid(); +// if (has) +// { +// // +// // Check Item Is not Exists ... +// idx = FindIndex( +// obFVG, +// waitingZones // +// ); +// has = !IsValidIndex(idx); +// if (has) +// { +// // +// // New Waiting Zone ... +// AddRef( +// obFVG, +// waitingZones // +// ); +// } +// else +// { +// // +// // Update Exists Waiting Zone ... +// waitingZones[idx].AddFVG(fvg); +// } +// } + +// // +// bar.Clean(); +// } +// } + +/////////////////////////////////////////////////////////////////////////////////// + +// +bool IsValidZone( + XOHCL &invalidBar, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + invalidBar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XCFVG *fvg; + result = GetMainFVG(fvg); + if (!result) + { + // + ZeroMemory(fvg); + return result; + } + + // + XOHCL startedBar; + bool isBodyOut = false; + result = fvg.IsStarted( + fvg.GetDirection(), + startedBar, + isBodyOut // + ); + if (!result) + { + // + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; + } + + // + XOHCL bar; + bool isBullish = fvg.IsBullish(); + + // + int fromIndex = iBarShift( + fvg.GetSymbol(), + fvg.GetPeriod(), + startedBar.NextAt() // + ); + result = IsValidIndex(fromIndex); + if (!result) + { + // + bar.Clean(); + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; + } + + // + bool isInited = false; + for (int i = barIndex; i < fromIndex; i++) + { + // + isInited = bar.Init( + fvg.GetSymbol(), + fvg.GetPeriod(), + i // + ); + if (!isInited) + { + // + bar.Clean(); + continue; + } + + // + bool isBarAbove = + bar.low > fvg.Upper(); + bool isBarBelow = + bar.high < fvg.Lower(); + + // + result = + isBullish + ? isBarAbove + : isBarBelow; + if (!result) + { + // + invalidBar = bar; + bar.Clean(); + + // + break; + } + + // + bar.Clean(); + } + + // + bar.Clean(); + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; +} + +/////////////////////////////////////////////////////////////////////////////////// + +// +// XBoxZone iBox; +// result = iOBFVG.ToZone(iBox); +// if (!result) +// { +// // +// iBox.Clean(); +// iOBFVG.Clean(); + +// // +// continue; +// } + +// +// XCFVG *fvg; +// result = iOBFVG.GetMainFVG(fvg); +// if (!result) +// { +// // +// iOBFVG.Clean(); +// ZeroMemory(fvg); + +// // +// continue; +// } + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// diff --git a/BKPS/14031218/Documents/BKP/Test.mq5 b/BKPS/14031218/Documents/BKP/Test.mq5 new file mode 100644 index 0000000..02e4a71 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/Test.mq5 @@ -0,0 +1,243 @@ +//+------------------------------------------------------------------+ +//| Test.mq5 | +//| Copyright 2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +// +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Classes/x-saherelm.x-poi.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" + +// +XCPOIDrawer *mPOIDrawer; +XCPOIDetector *mPOIDetector; +XCBarAnalyser *mBarAnalyser; + +// +XBarTracker mBarTracker; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + //--- + mPOIDetector = new XCPOIDetector( + _Symbol, + _Period // + ); + mPOIDetector.Init(); + + //--- + mPOIDrawer = new XCPOIDrawer(); + + //--- + mBarAnalyser = new XCBarAnalyser(); + + //--- + mBarTracker.Init( + _Symbol, + _Period // + ); + + //--- + return (INIT_SUCCEEDED); +} +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + //--- + ZeroMemory(mPOIDrawer); + ZeroMemory(mBarAnalyser); + ZeroMemory(mPOIDetector); +} +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + + // + bool isNewBar = mBarTracker.IsNewBar(); + if (!isNewBar) + { + return; + } + + // + ENUM_XPOI_EVENTS mPOIEvents[]; + mPOIDetector.Update(mPOIEvents); + + // + XPOIState mPOIState; + mPOIDetector.GetState(mPOIState); + + // + bool has = Contains( + X_BULLISH_FVG_DETECTED, + mPOIEvents // + ) || + Contains( + X_BEARISH_FVG_DETECTED, + mPOIEvents // + ); + if (has) + { + // + XCFVG *fvg; + int idx = GetYoungest(mPOIState.fairValueGaps); + has = IsValidIndex(idx); + if (has) + { + // + fvg = mPOIState.fairValueGaps[idx]; + + // + XCBaseObject *iObj; + has = mPOIDrawer.CreateFairValueGap( + fvg, + iObj // + ); + + // + if (has) + { + // + Print("New Fair Value Gap ..."); + } + } + } + + // // + // bool has = mPOIState.HasFairValueGaps(); + // if (has) + // { + // // + // int count = mPOIState.CountFairValueGaps(); + // for (int i = 0; i < count; i++) + // { + // // + // mPOIState.fairValueGaps[i].To(TimeCurrent()); + + // // + // XCBaseObject *iObj; + // bool isCreated = mPOIDrawer.CreateFairValueGap( + // mPOIState.fairValueGaps[i], + // iObj // + // ); + // } + + // + // Print("Salam"); + + // + return; + + // // + // XOHCL bar; + // bool isInited = bar.Init( + // _Symbol, + // _Period, + // 0 // + // ); + // if (!isInited) + // { + // return; + // } + + // // + // int index = 0; + // ENUM_X_DIRECTION sameBarDir; + // bool hasSameBars = mBarAnalyser.HasSameBars( + // bar, + // sameBarDir, + // index, + // 3 // + // ); + // if (hasSameBars) + // { + // } + + // // + // // Detect Fair Value Gap ... + // XOHCL fvgEndBar; + // XOHCL fvgStartBar; + // ENUM_X_DIRECTION fvgDir; + // bool hasFVG = mBarAnalyser.HasFairValueGap( + // bar, + // fvgStartBar, + // fvgEndBar, + // fvgDir, + // 3 // + // ); + // if (hasFVG) + // { + // // + // XCFVG *fvg; + // fvg = new XCFVG(); + // bool isInit = fvg.Init( + // fvgStartBar, + // fvgEndBar, + // fvgDir // + // ); + // // if (isInit) + // // { + // // // + // // XCBaseObject *iObj; + // // bool isCreated = mPOIDrawer.CreateFairValueGap( + // // fvg, + // // iObj // + // // ); + // // + // // // + // // if (isCreated) + // // { + // // } + // // } + // } + + // // + // XOHCL obBar; + // ENUM_X_DIRECTION obDir; + // bool hasOB = mBarAnalyser.HasOrderBlock( + // bar, + // obBar, + // obDir, + // 3 // + // ); + // if (hasOB) + // { + // // + // XCOrderBlock *ob; + // ob = new XCOrderBlock(); + // bool isInit = ob.Init( + // obBar, + // obDir // + // ); + // if (isInit) + // { + // // // + // // XCBaseObject *iObj; + // // bool isCreated = mPOIDrawer.CreateOrderBlock( + // // ob, + // // iObj // + // // ); + + // // // + // // if (isCreated) + // // { + // // Print("Order Block ..."); + // // } + // // } + // } + + // // + // } +} +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Documents/BKP/smc.ea.ex5 b/BKPS/14031218/Documents/BKP/smc.ea.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4a90a92740b1c0e879d2aacf5b51a38dd24e0f0b GIT binary patch literal 38680 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 +#include + +// +// Input parameters +input ENUM_TIMEFRAMES TimeFrame = PERIOD_M15; // Timeframe for analysis +input double RiskPercent = 1.0; // Risk per trade (1-2%) +input int ATR_Period = 14; // ATR period for volatility +input int OrderBlockLength = 20; // Bars for consolidation +input int ConfirmationCandles = 3; // Candles to confirm breakout +input double StopLossMultiplier = 1.5; // Stop loss buffer +input double TakeProfitRatio = 2.0; // Risk:Reward ratio +input int TrailingStopPips = 50; // Trailing stop in pips + +// +CTrade trade; +CAccountInfo accountInfo; + +// +double Ask = 0; +double Bid = 0; + +// +// Order Block structure +struct OrderBlock +{ + datetime startTime; + double high; + double low; +}; + +// +int atrHandler = INVALID_HANDLE; +int maFastHandler = INVALID_HANDLE; +int maSlowHandler = INVALID_HANDLE; + +// +double atrs[]; +double fastMAs[]; +double slowMAs[]; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // + trade.SetExpertMagicNumber(123456); // Unique magic number + + // + atrHandler = iATR(_Symbol, TimeFrame, ATR_Period); + maFastHandler = iMA(_Symbol, TimeFrame, 20, 0, MODE_SMA, PRICE_CLOSE); + maSlowHandler = iMA(_Symbol, TimeFrame, 50, 0, MODE_SMA, PRICE_CLOSE); + + // + bool isValid = + atrHandler != INVALID_HANDLE && + maFastHandler != INVALID_HANDLE && + maSlowHandler != INVALID_HANDLE; + if (!isValid) + { + return (INIT_FAILED); + } + + // + return (INIT_SUCCEEDED); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // + // Cleanup code if needed ... + IndicatorRelease(atrHandler); + IndicatorRelease(maFastHandler); + IndicatorRelease(maSlowHandler); + + // + ZeroMemory(atrs); + ZeroMemory(fastMAs); + ZeroMemory(slowMAs); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // Avoid multiple orders + if (CheckOpenOrders()) + return; + + // + CopyBuffer(atrHandler, MAIN_LINE, 0, 200, atrs); + + // + CopyBuffer(maFastHandler, MAIN_LINE, 0, 2, fastMAs); + CopyBuffer(maSlowHandler, MAIN_LINE, 0, 2, slowMAs); + + // + Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); // Get the Ask Price + Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); // Get the Bid Price + + // + // Check for trend and execute trades + if (IsUptrend()) + { + OrderBlock block = FindBullishOrderBlock(); + if (block.startTime != 0 && IsPriceInBlock(block)) + { + if (ConfirmBullishEntry()) + ExecuteTrade(block, ORDER_TYPE_BUY); + } + } + else if (IsDowntrend()) + { + OrderBlock block = FindBearishOrderBlock(); + if (block.startTime != 0 && IsPriceInBlock(block)) + { + if (ConfirmBearishEntry()) + ExecuteTrade(block, ORDER_TYPE_SELL); + } + } + + // Manage trailing stops + TrailStop(); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Check if price is within the order block | +//+------------------------------------------------------------------+ +bool IsPriceInBlock(OrderBlock &block) +{ + double currentPrice = (Ask + Bid) / 2; // Mid-price + return (currentPrice >= block.low && currentPrice <= block.high); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Detect uptrend using moving averages | +//+------------------------------------------------------------------+ +bool IsUptrend() +{ + // + double maFast = fastMAs[0]; + double maSlow = slowMAs[0]; + + // + return (maFast > maSlow); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Detect downtrend using moving averages | +//+------------------------------------------------------------------+ +bool IsDowntrend() +{ + // + double maFast = fastMAs[0]; + double maSlow = slowMAs[0]; + + // + return (maFast < maSlow); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Find bullish order blocks | +//+------------------------------------------------------------------+ +OrderBlock FindBullishOrderBlock() +{ + // + OrderBlock block; + block.startTime = 0; + + // + for (int i = 1; i < 100; i++) + { + double prevHigh = iHigh(NULL, TimeFrame, i); + double prevLow = iLow(NULL, TimeFrame, i); + double prevClose = iClose(NULL, TimeFrame, i); + double prevOpen = iOpen(NULL, TimeFrame, i); + + double atr = atrs[i]; + if (prevClose - prevOpen > 1.5 * atr) + { // Strong bullish candle + double consolidationHigh = prevHigh; + double consolidationLow = prevLow; + bool isConsolidation = true; + + for (int j = 1; j <= OrderBlockLength; j++) + { + double newHigh = iHigh(NULL, TimeFrame, i - j); + double newLow = iLow(NULL, TimeFrame, i - j); + consolidationHigh = MathMax(consolidationHigh, newHigh); + consolidationLow = MathMin(consolidationLow, newLow); + + if ((consolidationHigh - consolidationLow) > 0.5 * atr) + { + isConsolidation = false; + break; + } + } + + if (isConsolidation) + { + block.high = consolidationHigh; + block.low = consolidationLow; + block.startTime = iTime(NULL, TimeFrame, i); + return block; + } + } + } + return block; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Find bearish order blocks | +//+------------------------------------------------------------------+ +OrderBlock FindBearishOrderBlock() +{ + // + OrderBlock block; + block.startTime = 0; + + // + for (int i = 1; i < 100; i++) + { + double prevHigh = iHigh(NULL, TimeFrame, i); + double prevLow = iLow(NULL, TimeFrame, i); + double prevClose = iClose(NULL, TimeFrame, i); + double prevOpen = iOpen(NULL, TimeFrame, i); + + double atr = atrs[i]; + if (prevOpen - prevClose > 1.5 * atr) + { // Strong bearish candle + double consolidationHigh = prevHigh; + double consolidationLow = prevLow; + bool isConsolidation = true; + + for (int j = 1; j <= OrderBlockLength; j++) + { + double newHigh = iHigh(NULL, TimeFrame, i - j); + double newLow = iLow(NULL, TimeFrame, i - j); + consolidationHigh = MathMax(consolidationHigh, newHigh); + consolidationLow = MathMin(consolidationLow, newLow); + + if ((consolidationHigh - consolidationLow) > 0.5 * atr) + { + isConsolidation = false; + break; + } + } + + if (isConsolidation) + { + block.high = consolidationHigh; + block.low = consolidationLow; + block.startTime = iTime(NULL, TimeFrame, i); + return block; + } + } + } + return block; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Confirm bullish entry with candle pattern | +//+------------------------------------------------------------------+ +bool ConfirmBullishEntry() +{ + // + int shift = iBarShift(NULL, TimeFrame, TimeCurrent()); + double prevLow = iLow(NULL, TimeFrame, shift + 1); + double currentClose = iClose(NULL, TimeFrame, shift); + return (currentClose > prevLow && iOpen(NULL, TimeFrame, shift) < currentClose); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Confirm bearish entry with candle pattern | +//+------------------------------------------------------------------+ +bool ConfirmBearishEntry() +{ + // + int shift = iBarShift(NULL, TimeFrame, TimeCurrent()); + double prevHigh = iHigh(NULL, TimeFrame, shift + 1); + double currentClose = iClose(NULL, TimeFrame, shift); + return (currentClose < prevHigh && iOpen(NULL, TimeFrame, shift) > currentClose); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Execute trade with risk management | +//+------------------------------------------------------------------+ +void ExecuteTrade(OrderBlock &block, ENUM_ORDER_TYPE orderType) +{ + // + double atr = atrs[0]; + double stopLoss, takeProfit, lotSize; + double entryPrice = (orderType == ORDER_TYPE_BUY) ? Ask : Bid; + + // Calculate stop loss and take profit + if (orderType == ORDER_TYPE_BUY) + { + stopLoss = block.low - StopLossMultiplier * atr; + takeProfit = entryPrice + (entryPrice - stopLoss) * TakeProfitRatio; + } + else + { + stopLoss = block.high + StopLossMultiplier * atr; + takeProfit = entryPrice - (stopLoss - entryPrice) * TakeProfitRatio; + } + + // Calculate lot size based on risk + lotSize = CalculateLotSize(stopLoss, entryPrice, orderType); + if (lotSize <= 0) + return; + + // Place order + if (orderType == ORDER_TYPE_BUY) + { + trade.Buy(lotSize, _Symbol, entryPrice, stopLoss, takeProfit, "SMC Bullish Order Block"); + } + else + { + trade.Sell(lotSize, _Symbol, entryPrice, stopLoss, takeProfit, "SMC Bearish Order Block"); + } +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Calculate lot size based on risk per trade | +//+------------------------------------------------------------------+ +double CalculateLotSize(double stopLoss, double entryPrice, ENUM_ORDER_TYPE orderType) +{ + double riskAmount = AccountBalance() * RiskPercent / 100; + double stopLossPips = MathAbs((entryPrice - stopLoss) / SymbolInfoDouble(_Symbol, SYMBOL_POINT)); + + if (stopLossPips == 0) + return 0; + + double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); + double lotSize = riskAmount / (stopLossPips * pipValue); + lotSize = NormalizeDouble(lotSize, 2); // Adjust to symbol's lot precision + + return MathMax(lotSize, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Check for existing open orders | +//+------------------------------------------------------------------+ +bool CheckOpenOrders() +{ + for (int i = 0; i < PositionsTotal(); i++) + { + if (PositionGetSymbol(i) == _Symbol) + return true; + } + return false; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Trailing stop logic | +//+------------------------------------------------------------------+ +void TrailStop() +{ + for (int i = 0; i < PositionsTotal(); i++) + { + if (PositionGetSymbol(i) != _Symbol) + continue; + + ulong ticket = PositionGetInteger(POSITION_TICKET); + ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + double currentPrice = (type == POSITION_TYPE_BUY) ? Bid : Ask; + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double stopLoss = PositionGetDouble(POSITION_SL); + double trailingStopPrice = (type == POSITION_TYPE_BUY) + ? currentPrice - TrailingStopPips * SymbolInfoDouble(_Symbol, SYMBOL_POINT) + : currentPrice + TrailingStopPips * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + + // Update stop loss if price moves favorably + if ((type == POSITION_TYPE_BUY && trailingStopPrice > stopLoss) || + (type == POSITION_TYPE_SELL && trailingStopPrice < stopLoss)) + { + trade.PositionModify(ticket, trailingStopPrice, PositionGetDouble(POSITION_TP)); + } + } +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Calculate Account Balance | +//+------------------------------------------------------------------+ +double AccountBalance() +{ + return accountInfo.Balance(); +} +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Documents/BKP/testob.mq5 b/BKPS/14031218/Documents/BKP/testob.mq5 new file mode 100644 index 0000000..8910672 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/testob.mq5 @@ -0,0 +1,275 @@ +//+------------------------------------------------------------------+ +//| OrderBlockDetector.mq5| +//| Copyright 2023, MetaQuotes Software Corp. | +//| https://www.mql5.com| +//+------------------------------------------------------------------+ +#property strict + +// +// Input Parameters +input int ConsolidationPeriod = 20; // Bars for consolidation detection +input int AtrPeriod = 14; // ATR period for volatility +input double AtrMultiplier = 2.0; // Threshold multiplier (ATR * multiplier) +input int VolumeThreshold = 1000; // Minimum volume for breakout +input bool RequireRetest = true; // Retest confirmation required? +input int VpvrBars = 50; // Bars for VPVR calculation +input int TrendCheckPeriod = 30; // Bars for trend structure analysis +input int MACDFast = 12; // MACD Fast EMA period +input int MACDSlow = 26; // MACD Slow EMA period +input int MACDSignal = 9; // MACD Signal period +input int RSIPeriod = 14; // RSI period +input double RSILevel = 50; // RSI threshold level + +// Global Variables +int ObjectId = 0; +string Prefix = "OrderBlock_"; + +// +enum ENUM_X_DIRECTION +{ + X_DIRECTION_NONE, + X_DIRECTION_BULISH, + X_DIRECTION_BEARISH, +}; + +// +int atrHandler = INVALID_HANDLE; +double atrBuffer[]; + +// +int rsiHandler = INVALID_HANDLE; +double rsiBuffer[]; + +// +int macdHandler = INVALID_HANDLE; +double macdMainBuffer[]; +double macdSignalBuffer[]; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // + ArraySetAsSeries(atrBuffer, true); + atrHandler = iATR(_Symbol, _Period, AtrPeriod); + + // + ArraySetAsSeries(rsiBuffer, true); + rsiHandler = iRSI(_Symbol, _Period, RSIPeriod, PRICE_CLOSE); + + // + ArraySetAsSeries(macdMainBuffer, true); + ArraySetAsSeries(macdSignalBuffer, true); + macdHandler = iMACD(_Symbol, _Period, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE); + + // + ObjectsDeleteAll(0, Prefix); + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // + IndicatorRelease(atrHandler); + ObjectsDeleteAll(0, Prefix); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + DetectOrderBlocks(); +} + +//+------------------------------------------------------------------+ +//| Detect Order Blocks with ATR Dynamic Threshold | +//+------------------------------------------------------------------+ +void DetectOrderBlocks() +{ + double high, low, vpvrPrice, atr, dynamicThreshold; + datetime startTime, endTime; + bool isBullish, isBearish; + int bars = Bars(_Symbol, _Period); + + for (int i = ConsolidationPeriod; i < bars; i++) + { + // + // Get consolidation range + high = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, ConsolidationPeriod, i)); + low = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, ConsolidationPeriod, i)); + double range = high - low; + + // + // Calculate dynamic threshold using ATR + CopyBuffer(atrHandler, MAIN_LINE, i, 2, atrBuffer); + atr = atrBuffer[0]; + dynamicThreshold = atr * AtrMultiplier; + + // Check if consolidation range is within ATR-based threshold + if (range <= dynamicThreshold) + { + // VPVR Integration + vpvrPrice = CalculateVPVR(i, ConsolidationPeriod); + bool validVPVR = (vpvrPrice > low && vpvrPrice < high); + + // Check breakout direction + isBullish = iClose(_Symbol, _Period, i - ConsolidationPeriod) > high; + isBearish = iClose(_Symbol, _Period, i - ConsolidationPeriod) < low; + + // Trend Verification + ENUM_X_DIRECTION trend = CheckTrendStructure(TrendCheckPeriod); + + // MACD/RSI Verification + bool macdValid = CheckMACD(trend); + bool rsiValid = CheckRSI(trend); + + // Validate all conditions + if ((isBullish || isBearish) && validVPVR && + (trend != -1) && macdValid && rsiValid) + { + double breakoutVolume = (double)iVolume(_Symbol, _Period, i - ConsolidationPeriod); + if (breakoutVolume < VolumeThreshold) + continue; + + // Define order block time window + startTime = iTime(_Symbol, _Period, i); + endTime = iTime(_Symbol, _Period, i + ConsolidationPeriod); + + // Check retest (if required) + if (RequireRetest) + { + bool retestFound = false; + for (int j = i - ConsolidationPeriod; j > 0; j--) + { + if ((isBullish && iLow(_Symbol, _Period, j) <= low && iLow(_Symbol, _Period, j) >= high) || + (isBearish && iHigh(_Symbol, _Period, j) >= high && iHigh(_Symbol, _Period, j) <= low)) + { + retestFound = true; + break; + } + } + if (!retestFound) + continue; + } + + // Draw order block with ATR annotation + string name = Prefix + IntegerToString(ObjectId++); + DrawOrderBlock(name, startTime, endTime, low, high, + isBullish ? clrGreen : clrRed, vpvrPrice, dynamicThreshold); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Trend Detection using Price Structure | +//+------------------------------------------------------------------+ +ENUM_X_DIRECTION CheckTrendStructure(int period) +{ + int currentStart = 1; + int previousStart = period + 1; + + double currentHigh = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, period, currentStart)); + double previousHigh = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, period, previousStart)); + double currentLow = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, period, currentStart)); + double previousLow = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, period, previousStart)); + + if (currentHigh > previousHigh && currentLow > previousLow) + return (X_DIRECTION_BULISH); // Uptrend + else if (currentHigh < previousHigh && currentLow < previousLow) + return (X_DIRECTION_BEARISH); // Downtrend + else + return (X_DIRECTION_NONE); // No clear trend +} + +//+------------------------------------------------------------------+ +//| MACD Trend Verification | +//+------------------------------------------------------------------+ +bool CheckMACD(ENUM_X_DIRECTION trend) +{ + // + CopyBuffer(macdHandler, MAIN_LINE, 0, 1, macdMainBuffer); + CopyBuffer(macdHandler, SIGNAL_LINE, 0, 1, macdSignalBuffer); + double macdMain = macdMainBuffer[0]; + double macdSignal = macdSignalBuffer[0]; + + // + if (trend == X_DIRECTION_BULISH) + return (macdMain > macdSignal); + if (trend == X_DIRECTION_BEARISH) + return (macdMain < macdSignal); + return (false); +} + +//+------------------------------------------------------------------+ +//| RSI Trend Verification | +//+------------------------------------------------------------------+ +bool CheckRSI(ENUM_X_DIRECTION trend) +{ + // + CopyBuffer(rsiHandler, MAIN_LINE, 0, 1, rsiBuffer); + double rsiValue = rsiBuffer[0]; + + // + if (trend == X_DIRECTION_BULISH) + return (rsiValue > RSILevel); + if (trend == X_DIRECTION_BEARISH) + return (rsiValue < RSILevel); + return (false); +} + +//+------------------------------------------------------------------+ +//| Calculate VPVR High Volume Node | +//+------------------------------------------------------------------+ +double CalculateVPVR(int startIdx, int period) +{ + double maxVolume = 0; + double vpvrPrice = 0; + double price, volume; + + for (int i = startIdx; i < startIdx + period; i++) + { + price = (iHigh(_Symbol, _Period, i) + iLow(_Symbol, _Period, i)) / 2; + volume = (double)iVolume(_Symbol, _Period, i); + if (volume > maxVolume) + { + maxVolume = volume; + vpvrPrice = price; + } + } + return (vpvrPrice); +} + +//+------------------------------------------------------------------+ +//| Draw Order Block with ATR Annotation | +//+------------------------------------------------------------------+ +void DrawOrderBlock(string name, datetime startTime, datetime endTime, + double bottom, double top, color clr, double vpvrPrice, double atrThreshold) +{ + // Draw rectangle + ObjectCreate(0, name + "_rect", OBJ_RECTANGLE, 0, startTime, top, endTime, bottom); + ObjectSetInteger(0, name + "_rect", OBJPROP_COLOR, clr); + ObjectSetInteger(0, name + "_rect", OBJPROP_FILL, true); + ObjectSetInteger(0, name + "_rect", OBJPROP_BACK, true); + ObjectSetInteger(0, name + "_rect", OBJPROP_WIDTH, 2); + + // Draw VPVR marker + if (vpvrPrice > 0) + { + ObjectCreate(0, name + "_vpvr", OBJ_HLINE, 0, 0, vpvrPrice); + ObjectSetInteger(0, name + "_vpvr", OBJPROP_COLOR, clrYellow); + ObjectSetInteger(0, name + "_vpvr", OBJPROP_WIDTH, 1); + } + + // Add ATR threshold label + string atrLabel = StringFormat("ATR Threshold: %.5f", atrThreshold); + ObjectCreate(0, name + "_atr", OBJ_TEXT, 0, startTime, top); + ObjectSetString(0, name + "_atr", OBJPROP_TEXT, atrLabel); + ObjectSetInteger(0, name + "_atr", OBJPROP_COLOR, clrWhite); +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy 2.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy 2.mq5 new file mode 100644 index 0000000..1f79c25 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy 2.mq5 @@ -0,0 +1,2295 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "./x-121.smc.xwz.signal.lib.mq5" + +// +// Definition ... +class XCX121SMCXWZSignalDetector : public XCBase +{ + // + public: + // + // Props ... + X121SMCStrategyXWZWorkingZone workingZone; + X121SMCStrategyXWZSignalConditions mConditions; + X121SMCStrategyXWZSignalConditions mConditionsCollection[]; + + // + // Constructor(s) ... + XCX121SMCXWZSignalDetector( + string _symbol, + ENUM_TIMEFRAMES _period // + ) + { + // + symbol = _symbol; + period = _period; + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCXWZSignalDetector() + { + DeInit(); + } + + // + // + // + + // + // Detect Setup Conditions ... + bool DetectSignalSetup( + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + double maxAllowedSLDistanceInPoint = 300 + // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + // + mConditions.Clean(); + + // + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + mConditions.symbol = symbol; + mConditions.period = period; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + XOHCL consolidationZBar; + result = consolidationCycleHelper.GetBar( + consolidationZBar, + zIndex // + ); + if (!result) + { + // + consolidationZBar.Clean(); + return result; + } + + // + bool drawBar = false; + if (drawBar) + { + // + DrawBar( + consolidationZBar, + decisionCycleHelper.mPOIDrawer // + ); + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Scores ... + + // + // Decision ... + double decisionBullishScore = 0; + double decisionBearishScore = 0; + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + double analyseBullishScore = 0; + double analyseBearishScore = 0; + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // + // + + // + bool hasNewSupply = Contains( + X_SUPPLY_ZONE_DETECTED, + analysePoiEvents // + ); + + // + bool hasNewDemand = Contains( + X_DEMAND_ZONE_DETECTED, + analysePoiEvents // + ); + + // + bool hasNewFairValueGap = + Contains( + X_BULLISH_FVG_DETECTED, + analysePoiEvents // + ) || + Contains( + X_BEARISH_FVG_DETECTED, + analysePoiEvents // + ); + + // + bool hasNewOrderBlock = + Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + analysePoiEvents // + ) || + Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + analysePoiEvents // + ); + + // + // + // + + // + // Select Drawer Class ... + XCPOIDrawer *drawer = visionCycleHelper.mPOIDrawer; + + // + // Setup Conditions ... + double sls[]; + double sl = 0; + double pivot = 0; + double point = 0; + double targets[]; + double reward = 0; + XBoxZone signalBox; + double amountPercent = 0; + bool hasPriority = false; + bool hasSignalBox = false; + bool hasRewardAmount = false; + bool isSignalBoxReversal = false; + bool hasWorkingZoneOveralDirection = false; + ENUM_X_DIRECTION wzOveralDir = X_DIRECTION_NONE; + ENUM_X_DIRECTION signalBoxDir = X_DIRECTION_NONE; + ENUM_X121SMC_XWZ_PRIORITY priority = X121SMC_XWZ_PRIORITY_NONE; + ENUM_X121SMC_XWZ_PROVIDERS provider = X121SMC_XWZ_PROVIDER_NONE; + + // + // + // + + // + // First We Have to Has Working Zone ... + bool hasWorkingZone = workingZone.IsValid(); + if (!hasWorkingZone) + { + // + hasWorkingZone = workingZone.Init( + symbol, + period, + zIndex, + visionState, + consolidationState, + analyseState, + decisionState // + ); + } + + // + // Update Working Zone ... + if (hasWorkingZone) + { + // + // Reset POI Detector Required POI(s) ... + visionCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + analyseCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + decisionCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + consolidationCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + + // + // Reset POI Detector Allowed Loopback ... + visionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + analyseCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + decisionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + consolidationCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + + // + // Update Working Zone ... + // workingZone.Update( + // zIndex, + // visionState, + // consolidationState, + // analyseState, + // decisionState // + // ); + + // + // Check Working Zone Overal Direction ... + hasWorkingZoneOveralDirection = workingZone + .DetectOveralDirection(wzOveralDir); + + // + // Checking Working Zone Destory or not ... + bool isWorkingZoneDestroyed = workingZone.IsDestroyed( + zIndex, + period // + ); + + // + // Cleanup WorkingZone and ignore all conditions ... + if (isWorkingZoneDestroyed) + { + // + result = false; + workingZone.Clean(); + hasWorkingZone = false; + + // + // Cleanup Resources ... + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + } + + // + // + // + + // + // Waiting Box Detected ... + bool hasWaitingBoxes = hasWorkingZone && + workingZone.HasWaitingBoxes(); + if (hasWaitingBoxes) + { + // + XOHCL zBar; + XOHCL cBar; + XOHCL pBar; + int count = 0; + int idx = -1; + bool has = false; + + // + bool isInited = zBar.Init( + symbol, + period, + zIndex // + ); + isInited = + isInited && + zBar.GetPreviousBar(cBar); + isInited = + isInited && + cBar.GetPreviousBar(pBar); + + // + count = workingZone.CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = workingZone.waitingBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + // Check Price Rejection ... + + // + bool hasBullishFiboPressure = + decisionCycleHelper + .mBarAnalyser + .HasFiboPressure( + cBar, + X_DIRECTION_BULLISH, + X_FIBO_LEVEL_382 // + ); + + // + bool hasBearishFiboPressure = + decisionCycleHelper + .mBarAnalyser + .HasFiboPressure( + cBar, + X_DIRECTION_BEARISH, + X_FIBO_LEVEL_382 // + ); + + // + // Bullish Rejection ... + bool isBullishRejected = + // + isInited && + isBullish && + cBar.low < pBar.low && + zBar.low > iBox.upper && + cBar.low <= iBox.upper && + zBar.open > iBox.upper && + hasBullishFiboPressure && + cBar.GetLowShadow() > pBar.GetLowShadow() + // + ; + + // + // Bearish Rejection ... + bool isBearishhRejected = + // + isInited && + !isBullish && + cBar.high > pBar.high && + zBar.open < iBox.lower && + zBar.high < iBox.lower && + hasBearishFiboPressure && + cBar.high >= iBox.lower && + cBar.GetHighShadow() > pBar.GetHighShadow() + // + ; + + // + has = isBullishRejected || + isBearishhRejected; + if (has) + { + // + idx = i; + signalBox = iBox; + hasSignalBox = has; + signalBox.to = cTime; + signalBoxDir = iBox.dir; + isSignalBoxReversal = false; + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE; + } + + // + iBox.Clean(); + } + + // + // Remove Signal Box from Waiting Boxes of + // Working Zone ... + if (hasSignalBox) + { + // + if (IsValidIndex(idx)) + { + // + ArrayRemove( + workingZone.waitingBoxes, + idx, + 1 // + ); + } + } + + // + // Ignore Zone's Signals ... + hasSignalBox = false; + + // + // Cleanup Resources ... + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + } + + // + // Check Conditions if Has Inside Boxes ... + bool hasInsideBoxes = hasWorkingZone && + workingZone.HasInsideBoxes(); + if (hasInsideBoxes) + { + } + + // + // Check Conditions if has Breaked Boxes ... + bool hasBreakedBoxes = hasWorkingZone && + workingZone.HasBreakedBoxes(); + if (hasBreakedBoxes) + { + } + + // + // Checking Other Conditions ... + if (!hasSignalBox) + { + // + // Senari A ... + // hasSignalBox = hasWorkingZone && + // workingZone.DetectSenarioASignalBox( + // signalBox, + // signalBoxDir, + // decisionXConditions, + // analyseXConditions, + // decisionCycleHelper, + // drawer, + // zIndex // + // ); + // if (hasSignalBox) + // { + // // + // signalBox.to = cTime; + // isSignalBoxReversal = false; + // provider = X121SMC_XWZ_PROVIDER_PV_ZONE; + // } + + // // + // // Validating Signal Box if Exists ... + // if (hasSignalBox) + // { + // // + // // Validate Signal Boxes using Inside Box ... + // if (hasInsideBoxes) + // { + // // + // int idx = -1; + // bool has = false; + + // // + // idx = + // IsBullish(signalBoxDir) + // ? GetLowest(workingZone.insideBoxes) + // : GetHighest(workingZone.insideBoxes); + // has = IsValidIndex(idx); + // if (has) + // { + // // + // hasSignalBox = + // signalBoxDir == workingZone.insideBoxes[idx].dir; + // } + // } + + // // + // // Validate Signal Box Using Overal Trend ... + // if (hasWorkingZoneOveralDirection) + // { + // // + // hasSignalBox = + // signalBoxDir == wzOveralDir; + // } + // } + } + + // + // + // + + // + // Cleanup Signal if UnApproved ... + if (!hasSignalBox) + { + // + signalBox.Clean(); + signalBoxDir = X_DIRECTION_NONE; + } + + // + // + // + + // + // Check Priority Exists ... + hasPriority = workingZone + .DetectPriority( + priority, + signalBoxDir, + zIndex, + period // + ); + + // + // Check Price Reward and Amount Exists ... + hasRewardAmount = CalculateRiskReward( + priority, + reward, + amountPercent // + ); + + // + // Check Signal Conditions ... + if (hasSignalBox) + { + // + int idx = -1; + bool has = false; + + // + XCBoxObject *iObj; + has = drawer.DrawBox( + signalBox, + iObj // + ); + if (has) + { + // + iObj.BoxWidth(1); + iObj.BoxColor(clrYellow); + iObj.BoxStyle(STYLE_SOLID); + } + + // + isBullish = IsBullish(signalBoxDir); + isBearish = IsBearish(signalBoxDir); + + // + pivot = isBullish + ? signalBox.lower + : signalBox.upper; + + // + point = isBullish + ? signalBox.upper + : signalBox.lower; + + // + double iSL = 0; + double signalBoxRange = (signalBox.upper - signalBox.lower); + if (signalBoxRange < points * 100) + { + iSL = pivot; + } + else + { + iSL = signalBox.lower + (signalBox.upper - signalBox.lower) / 2; + } + + // + if (provider == X121SMC_XWZ_PROVIDER_PV_ZONE) + { + } + + // + Add( + iSL, + sls // + ); + + // + // Select Condition SL ... + + // + double entry = GetEntry( + signalBox.symbol, + signalBoxDir // + ); + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double longSL = slsMin; + double shortSL = slsMax; + + // + sl = isBullish + ? longSL + : shortSL; + + // + // Targets ... + + // + // Force Add TP 2 as Target ... + double risk = MathAbs(entry - sl); + double reward2 = 2 * risk; + // double iTP2 = isBullish + // ? entry + reward2 + // : entry - reward2; + // Add( + // iTP2, + // targets // + // ); + + // + // Based On Priority ... + has = priority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + XBoxZone waitingBoxes[]; + has = workingZone.HasWaitingBoxes(); + if (has) + { + // + Copy( + workingZone.waitingBoxes, + waitingBoxes // + ); + + // + while (HasChild(waitingBoxes)) + { + // + XBoxZone iBox; + idx = GetYoungest(waitingBoxes); + has = IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + iBox = waitingBoxes[idx]; + ArrayRemove( + waitingBoxes, + idx, + 1 // + ); + + // + bool hasInside = workingZone.HasInsideBox(iBox); + if (!hasInside) + { + continue; + } + + // + double iTarget = + IsBullish(signalBoxDir) + ? iBox.lower + : iBox.upper; + + // + Add( + iTarget, + targets // + ); + + // + iBox.Clean(); + } + } + } + + // + // Summarize Results ... + result = hasPriority && + hasSignalBox && + hasRewardAmount; + + // + if (result) + { + // + Copy( + sls, + mConditions.sls // + ); + Copy( + targets, + mConditions.targets // + ); + + // + mConditions.sl = sl; + mConditions.pivot = pivot; + mConditions.point = point; + mConditions.reward = reward; + mConditions.setupTime = cTime; + mConditions.dir = signalBoxDir; + mConditions.priority = priority; + mConditions.provider = provider; + mConditions.signalBox = signalBox; + mConditions.amountPercent = amountPercent; + } + + // + UpdateTo(cTime); + + // + // Draw Working Zone ... + if (hasWorkingZone) + { + // + workingZone.Draw( + drawer, + // + true, // Draw Waiting Boxes ... + true, // Draw Inside Boxes ... + true, // Draw Breaked Boxes ... + true, // Draw Breaked Inside Boxes ... + // + true, // Draw Supply Zone ... + true, // Draw Demand Zone ... + true, // Draw Supply Zones ... + true, // Draw Demand Zones ... + true, // Draw Support Zones ... + true // Draw Resistance Zones ... + ); + } + + // + // + // + + // + // Cleanup Resources ... + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + consolidationZBar.Clean(); + + // + return result; + } + + // + // Detect Trigger Conditions ... + bool DetectSignalTrigger( + // + X121SMCStrategyXWZSignalConditions &conditions, + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 + // + ) + { + // + bool result = false; + + // + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + return result; + } + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + // Cleanup ... + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + + // + double iAtr = decisionXConditions.atrBuffer[1]; + iAtr *= 1.5; + + // + // Check Signal Validation ... + // IMPORTANT: since all Validations done in SetUp Process ... + // here we only Execute Signal ... + + // + result = isBullish || + isBearish; + + // + if (result) + { + // + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + } + + // + // Cleanup ... + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionState.Clean(); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseState.Clean(); + analyseConditions.Clean(); + analyseXConditions.Clean(); + + // + return result; + } + + // + // Detect Guards ... + bool DetectGuards( + // + X121SMCGuard &guards[], + const XPosition &positions[], + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // + ) + { + // + bool result = false; + return false; + + // + Clean(guards); + + // + bool isCycleHelpersValid = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + + // + // Set Provider for Common Guards ... + string provider = ToString(X_121_SMC_PROVIDER_XWZ); + + // + // Check Cycle Helpers Validation ... + result = isCycleHelpersValid; + if (!result) + { + return result; + } + + // + // Select Own Positions ... + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + provider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + // Check Extracted Positions ... + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + // Validate Own Positions ... + result = IsValidSize(count); + if (!result) + { + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + return result; + } + + // + // + // + + // + // Get Global and Common Guards ... + + // + ENUM_X_121_SMC_GUARD_ACTIONS ignoreGuards[1] = { + X_121_SMC_GUARD_ACTION_TRAIL_STOP // + }; + result = DetectX121SMCGuards( + provider, + guards, + positions, + decisionCycleHelper, + analyseCycleHelper, + consolidationCycleHelper, + visionCycleHelper, + // + ignoreGuards + // + ); + + // + // + // + + // + // Implement Custom Implemented Guards ... + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Detect Required Data for Analyse Market to Guard Positions ... + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + consolidationConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + consolidationConditions.Clean(); + + // + Clean(visionPoiEvents); + Clean(visionCycleEvents); + + // + visionConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Cycles POI States ... + XPOIState visionState = visionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState consolidationState = consolidationConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions visionXConditions = visionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + + // + // + // + + // + // Selected Consolidation Zones ... + + // + int idx = -1; + bool has = false; + + // + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + has = decisionState.HasBullishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(decisionState.bullishConsolidationZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + bullishConsolidationZone = decisionState.bullishConsolidationZones[idx]; + } + } + + // + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + has = decisionState.HasBearishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(decisionState.bearishConsolidationZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + bearishConsolidationZone = decisionState.bearishConsolidationZones[idx]; + } + } + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Available Guards: + // X_121_SMC_GUARD_ACTION_NONE + // X_121_SMC_GUARD_ACTION_CLOSE + // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // X_121_SMC_GUARD_ACTION_HEDGE + + // + // X_121_SMC_GUARD_ACTION_CLOSE: + // Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // Close All Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // Close All Long Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // Close All Short Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // Partial Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // Trail Stop Specified Position on Specified Conditions ... + bool handleStoptrailingBasedOnConsolidationZones = true; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + bool isLong = IsLong(iPosition.type); + bool isInProfit = iPosition.profit > 0; + + // + double sl = iPosition.sl; + double tp = iPosition.tp; + + // + // Trail Stops Using Consolidation Zones ... + + // + bool canTraiLonglUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (isLong && + isInProfit && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > iPosition.sl && + bullishConsolidationZone.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingCZone) + { + sl = bullishConsolidationZone.lower; + } + + // + bool canTraiShortlUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (!isLong && + isInProfit && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < iPosition.sl && + bearishConsolidationZone.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingCZone) + { + sl = bearishConsolidationZone.upper; + } + + // + bool canTrailUsingCZone = + canTraiLonglUsingCZone || + canTraiShortlUsingCZone; + + // + bool isSLPassed = + sl > 0 && + (isLong + ? iPosition.price - sl >= points * 15 + : sl - iPosition.price >= points * 15); + + // + bool canTrail = + isSLPassed && + canTrailUsingCZone; + if (canTrail) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.ticket = iPosition.ticket; + + // + iGuard.sl = sl; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // Trail Target Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_HEDGE: + // Hedge all Positions on Specified Conditions ... + + // + // Cleanup Collections ... + + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + // + // Add Conditions to Conditions Collection ... + int AddConditionsIfNotExists( + int maxAllowed = 10 // + ) + { + // + int result = 0; + + // + bool isSetuped = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(mConditionsCollection); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXWZSignalConditions tmpItems[]; + Copy( + mConditionsCollection, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(mConditions.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXWZSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = mConditions.dir == iItem.dir && + mConditions.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + mConditionsCollection, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + mConditions, + mConditionsCollection // + ); + + // + // Remove Olds ... + CleanupArray( + mConditionsCollection, + maxAllowed // + ); + + // + result = ArraySize(mConditionsCollection); + + // + return result; + } + + // + // Draw Functions ... + // + + // + void DrawBar( + XOHCL &bar, + XCPOIDrawer *drawer, + bool forceClean = true // + ) + { + // + if (forceClean) + { + mBarObjects.Clear(); + } + + // + if (drawer == NULL || + !bar.IsValid()) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + + // + int widthBar = 2; + bool fillShadowsBar = true; + ENUM_LINE_STYLE styleBar = STYLE_SOLID; + color clrBar = + isBullish + ? clrAqua + : clrMagenta; + + // + datetime to = bar.NextAt(); + + // + XCOHCLObject *iObj; + bool isCreated = drawer + .CreateBar( + bar, + iObj, + to // + ); + if (isCreated) + { + // + iObj.BarSpes( + widthBar, + clrBar, + styleBar // + ); + + // + iObj.LowShadowFill(fillShadowsBar); + iObj.HighShadowFill(fillShadowsBar); + + // + mBarObjects.Add(iObj); + } + } + + // + protected: + // + + // + private: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + CArrayObj mObjects; + CArrayObj mBarObjects; + CArrayObj mWorkingZoneObjects; + + /** + * Initialize ... + */ + void Init() + { + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + mConditions.Clean(); + workingZone.Clean(); + Clean(mConditionsCollection); + + // + mBarObjects.Clear(); + } + + /** + * Update To Time of Exists Components ... + * + * @param value: updated time ... + */ + void UpdateTo( + datetime value = NULL // + ) + { + // + value = NormalizeTime(value); + + // + workingZone.UpdateTo(value); + } + + // + // Helpers ... + + // + bool CalculateRiskReward( + ENUM_X121SMC_XWZ_PRIORITY priority, + double &reward, + double &amountPercent // + ) + { + // + bool result = false; + + // + reward = 0; + amountPercent = 0; + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE; + if (!result) + { + return result; + } + + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + reward = 6; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + reward = 4; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + reward = 3; + amountPercent = 1.5; + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + reward = 2; + amountPercent = 1; + break; + + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + reward = 1; + amountPercent = 0.5; + break; + } + + // + result = + // + reward > 0 && + amountPercent > 0 + // + ; + + // + return result; + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy.mq5 new file mode 100644 index 0000000..c1e8cc2 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class copy.mq5 @@ -0,0 +1,2124 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "./x-121.smc.xwz.signal.lib.mq5" + +// +// Definition ... +class XCX121SMCXWZSignalDetector : public XCBase +{ + // + public: + // + // Props ... + X121SMCStrategyXWZWorkingZone workingZone; + X121SMCStrategyXWZSignalConditions mConditions; + X121SMCStrategyXWZSignalConditions mConditionsCollection[]; + + // + // Constructor(s) ... + XCX121SMCXWZSignalDetector( + string _symbol, + ENUM_TIMEFRAMES _period // + ) + { + // + symbol = _symbol; + period = _period; + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCXWZSignalDetector() + { + DeInit(); + } + + // + // + // + + // + // Detect Setup Conditions ... + bool DetectSignalSetup( + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + double maxAllowedSLDistanceInPoint = 300 + // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + // + mConditions.Clean(); + + // + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + mConditions.symbol = symbol; + mConditions.period = period; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + XOHCL consolidationZBar; + result = consolidationCycleHelper.GetBar( + consolidationZBar, + zIndex // + ); + if (!result) + { + // + consolidationZBar.Clean(); + return result; + } + + // + bool drawBar = false; + if (drawBar) + { + // + DrawBar( + consolidationZBar, + decisionCycleHelper.mPOIDrawer // + ); + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Select Drawer Class ... + XCPOIDrawer *drawer = visionCycleHelper.mPOIDrawer; + + // + // Setup Conditions ... + double sls[]; + double pivot = 0; + double point = 0; + double targets[]; + double reward = 0; + XBoxZone signalBox; + XOBFVG selectedZone; + double amountPercent = 0; + bool hasPriority = false; + bool hasSignalBox = false; + bool hasRewardAmount = false; + bool hasSelectedZone = false; + bool isSignalBoxReversal = false; + bool isSelectedZoneReversal = false; + bool hasSelectedConsolidationZone = false; + XConsolidationZone selectedConsolidationZone; + ENUM_X_DIRECTION selectedZoneDir = X_DIRECTION_NONE; + ENUM_X121SMC_XWZ_PRIORITY priority = X121SMC_XWZ_PRIORITY_NONE; + ENUM_X121SMC_XWZ_PROVIDERS provider = X121SMC_XWZ_PROVIDER_NONE; + + // + // First We Have to Has Working Zone ... + bool hasWorkingZone = workingZone.IsValid(); + if (!hasWorkingZone) + { + // + hasWorkingZone = workingZone.Init( + symbol, + period, + zIndex, + visionState, + consolidationState, + analyseState, + decisionState // + ); + } + + // + if (hasWorkingZone) + { + // + visionCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + analyseCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + decisionCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + consolidationCycleHelper.mPOIDetector.MaxRequiredPOIs(50); + + // + visionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + analyseCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + decisionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + consolidationCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(578); + + // + workingZone.Update( + zIndex, + visionState, + consolidationState, + analyseState, + decisionState // + ); + } + + // + bool hasWaitingZones = hasWorkingZone && + workingZone.HasWaitingZones(); + + // + // + // + + // + // Check Conditions if Has Inside Zones ... + bool hasInsideZones = hasWorkingZone && + workingZone.HasInsideZones(); + if (hasInsideZones) + { + // + int selectedIDX = -1; + int count = workingZone.CountInsideZones(); + for (int i = 0; i < count; i++) + { + // + bool has = DetectSelectedZoneConditions( + isSelectedZoneReversal, + workingZone.insideZones[i], + decisionState, + decisionXConditions // + ); + + // + if (has) + { + // + selectedIDX = i; + selectedZone = workingZone.insideZones[i]; + + // + break; + } + } + + // + if (IsValidIndex(selectedIDX)) + { + // + ArrayRemove( + workingZone.insideZones, + selectedIDX, + 1 // + ); + + // + hasSelectedZone = selectedZone.IsValid(); + provider = X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE; + } + } + + // + // Check Conditions if Has Breaked Zones ... + // bool hasBreakedZones = hasWorkingZone && + // workingZone.HasBreakedZones(); + // if (hasBreakedZones) + // { + // // + // if (!hasSelectedZone) + // { + // // + // int selectedIDX = -1; + // int count = workingZone.CountBreakedZones(); + // for (int i = 0; i < count; i++) + // { + // // + // bool has = DetectSelectedZoneConditions( + // isSelectedZoneReversal, + // workingZone.breakedZones[i], + // decisionState, + // decisionXConditions // + // ); + + // // + // if (has) + // { + // // + // selectedIDX = i; + // selectedZone = workingZone.breakedZones[i]; + + // // + // break; + // } + // } + + // // + // if (IsValidIndex(selectedIDX)) + // { + // // + // ArrayRemove( + // workingZone.breakedZones, + // selectedIDX, + // 1 // + // ); + + // // + // hasSelectedZone = selectedZone.IsValid(); + // provider = X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE; + // } + // } + // } + + // + // + // + + // + bool hasInsideBoxes = hasWorkingZone && + workingZone.HasInsideBoxes(); + if (hasInsideBoxes) + { + // + XOHCL zBar; + XOHCL cBar; + int count = 0; + bool has = false; + XBoxZone tmpSelectedBox; + int tmpSelectedBoxIDX = -1; + + // + has = zBar.Init( + symbol, + period, + zIndex // + ); + has = has && + zBar.GetPreviousBar(cBar); + if (has) + { + // + count = workingZone.CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + tmpSelectedBox = workingZone.insideBoxes[i]; + + // + bool isBullish = tmpSelectedBox.IsBullish(); + bool isBearish = tmpSelectedBox.IsBearish(); + + // + bool hasFiboPressure = + visionCycleHelper + .mBarAnalyser + .HasFiboPressure( + cBar, + tmpSelectedBox.dir, + X_FIBO_LEVEL_382 // + ); + + // + bool isBullishRejectedUpper = + cBar.low < tmpSelectedBox.upper && + cBar.GetDown() > tmpSelectedBox.upper; + + // + bool isBullishRejectedLower = + cBar.low < tmpSelectedBox.lower && + cBar.GetDown() > tmpSelectedBox.lower; + + // + bool isBearishRejectedUpper = + cBar.high > tmpSelectedBox.upper && + cBar.GetUp() < tmpSelectedBox.upper; + + // + bool isBearishRejectedLower = + cBar.high > tmpSelectedBox.lower && + cBar.GetUp() < tmpSelectedBox.lower; + + // + bool isBullishRejected = + // isBullishRejectedUpper || + isBullishRejectedLower; + + // + bool isBearishRejected = + isBearishRejectedUpper + // || isBearishRejectedLower + ; + + // + bool isMaWapBullish = + // + (decisionXConditions.isX3MaBullishState && + decisionXConditions.isX3MaBullishOrdered) + // + && + // + (decisionXConditions.isVWapBullishState && + decisionXConditions.isVWapBullishOrdered) + // + ; + + // + bool isMaWapBearish = + // + (decisionXConditions.isX3MaBearishState && + decisionXConditions.isX3MaBearishOrdered) + // + && + // + (decisionXConditions.isVWapBearishState && + decisionXConditions.isVWapBearishOrdered) + // + ; + + // + bool isX2MaWapInside = + // + (decisionXConditions.x3maFastBuffer[cIndex] < tmpSelectedBox.upper && + decisionXConditions.x3maMidBuffer[cIndex] < tmpSelectedBox.upper && + decisionXConditions.x3maFastBuffer[cIndex] > tmpSelectedBox.lower && + decisionXConditions.x3maMidBuffer[cIndex] > tmpSelectedBox.lower) + // + && + // + (decisionXConditions.vwapFastBuffer[cIndex] < tmpSelectedBox.upper && + decisionXConditions.vwapMidBuffer[cIndex] < tmpSelectedBox.upper && + decisionXConditions.vwapFastBuffer[cIndex] > tmpSelectedBox.lower && + decisionXConditions.vwapMidBuffer[cIndex] > tmpSelectedBox.lower) + // + ; + + // + bool isBullishConditions = + // + isBullish && + isMaWapBearish && + isX2MaWapInside && + hasFiboPressure && + isBullishRejected && + cBar.low < cBar.GetDown() + // + ; + + // + bool isBearishConditions = + // + isBearish && + isMaWapBullish && + isX2MaWapInside && + hasFiboPressure && + isBearishRejected && + cBar.high > cBar.GetUp() + // + ; + + // + has = isBullishConditions || + isBearishConditions; + if (!has) + { + // + tmpSelectedBox.Clean(); + continue; + } + + // + tmpSelectedBoxIDX = i; + signalBox = tmpSelectedBox; + + // + tmpSelectedBox.Clean(); + break; + } + } + + // + isSignalBoxReversal = false; + hasSignalBox = signalBox.IsValid(); + if (hasSignalBox) + { + // + ArrayRemove( + workingZone.insideBoxes, + tmpSelectedBoxIDX, + 1 // + ); + } + + // + zBar.Clean(); + cBar.Clean(); + tmpSelectedBox.Clean(); + } + + // + bool hasBreakedBoxes = hasWorkingZone && + workingZone.HasBreakedBoxes(); + if (hasBreakedBoxes) + { + } + + // + if (!hasSignalBox) + { + } + + // + // + // + + // + // Double Check and Prepare Signal Conditions ... + // including Targets and SLs ... + + // + if (hasSelectedZone) + { + // + int idx = -1; + bool has = false; + + // + // Check Consolidation Zones for SL Handling ... + selectedZoneDir = + !isSelectedZoneReversal + ? selectedZone.GetDirection() + : Opposit(selectedZone.GetDirection()); + bool isSelectedZonDirBullish = IsBullish(selectedZoneDir); + + // + if (isSelectedZoneReversal) + { + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH; + } + + // + // Calculate Priority ... + hasPriority = + hasWorkingZone && + workingZone + .DetectPriority( + priority, + selectedZoneDir, + zIndex, + period // + ); + + // + // Calculate Risk Reward Ration based on Priority ... + hasRewardAmount = CalculateRiskReward( + priority, + reward, + amountPercent // + ); + + // + // Calculate Pivot and Point ... + + // + pivot = + isSelectedZonDirBullish + ? selectedZone.ob.Lower() + : selectedZone.ob.Upper(); + + // + point = + isSelectedZonDirBullish + ? selectedZone.ob.Upper() + : selectedZone.ob.Lower(); + + // + // Detect Targets ... + DetectSelectedZonesTargets( + targets, + selectedZone, + selectedZoneDir, + priority, + workingZone, + zIndex // + ); + + // + // Detect SLs ... + double iAtr = decisionXConditions.atrBuffer[0]; + iAtr *= 1.5; + + // + // Default SL is Pivot ... + if (pivot > 0) + { + // + Add( + pivot, + sls // + ); + + // + double iSL = iAtr * pivot; + Add( + iSL, + sls // + ); + } + + // + DetectSelectedZoneSLCandidates( + sls, + selectedZone, + selectedZoneDir, + workingZone, + decisionXConditions, + zIndex, + maxAllowedSLDistanceInPoint // + ); + + // + // Summaries Conditions ... + result = + pivot > 0 && + point > 0 && + hasPriority && + hasRewardAmount && + HasDirection(selectedZoneDir); + if (result) + { + // + isBullish = IsBullish(selectedZoneDir); + isBearish = IsBearish(selectedZoneDir); + + // + Copy( + sls, + mConditions.sls // + ); + Copy( + targets, + mConditions.targets // + ); + + // + mConditions.pivot = pivot; + mConditions.point = point; + mConditions.reward = reward; + mConditions.setupTime = cTime; + mConditions.priority = priority; + mConditions.provider = provider; + mConditions.dir = selectedZoneDir; + mConditions.signalBox = signalBox; + mConditions.amountPercent = amountPercent; + } + + // + // Cleanup Resources ... + + // + Clean(sls); + Clean(targets); + selectedZone.Clean(); + selectedConsolidationZone.Clean(); + } + + // + if (hasSignalBox) + { + // // + // workingZone.mInsideZoneObjects.Clear(); + // workingZone.mBreakedZoneObjects.Clear(); + // workingZone.mWaitingZoneObjects.Clear(); + // workingZone.mWorkingZoneObjects.Clear(); + + // // + // XCBoxObject *iObj; + // signalBox.to = cTime; + // bool isCreated = drawer.CreateBox( + // signalBox, + // iObj // + // ); + + // // + // if (isCreated) + // { + // // + // iObj.BoxWidth(2); + // iObj.BoxColor(clrYellow); + // iObj.BoxStyle(STYLE_SOLID); + // } + + // // + // bool isSignalBoxBullishDir = signalBox.IsBullish(); + + // // + // // Calculate Priority ... + // hasPriority = + // hasWorkingZone && + // workingZone + // .DetectPriority( + // priority, + // signalBox.dir, + // zIndex, + // period // + // ); + + // // + // // Calculate Risk Reward Ration based on Priority ... + // hasRewardAmount = CalculateRiskReward( + // priority, + // reward, + // amountPercent // + // ); + + // // + // // Calculate Pivot and Point ... + + // // + // pivot = + // isSignalBoxBullishDir + // ? signalBox.lower + // : signalBox.upper; + + // // + // point = + // isSignalBoxBullishDir + // ? signalBox.upper + // : signalBox.lower; + + // // + // double defaultTarget = + // isSignalBoxBullishDir + // ? signalBox.upper + // : signalBox.lower; + // Add( + // defaultTarget, + // targets // + // ); + + // // + // // Detect SLs ... + // double iAtr = decisionXConditions.atrBuffer[0]; + // iAtr *= 1.5; + + // // + // double defaultSL = + // isSignalBoxBullishDir + // ? decisionXConditions.valesBuffer[0] - iAtr + // : decisionXConditions.peaksBuffer[0] + iAtr; + + // // + // Add( + // defaultSL, + // sls // + // ); + + // // + // // Summaries Conditions ... + // result = + // pivot > 0 && + // point > 0 && + // hasPriority && + // hasRewardAmount; + // if (result) + // { + // // + // isBullish = signalBox.IsBullish(); + // isBearish = signalBox.IsBearish(); + + // // + // Copy( + // sls, + // mConditions.sls // + // ); + // Copy( + // targets, + // mConditions.targets // + // ); + + // // + // mConditions.pivot = pivot; + // mConditions.point = point; + // mConditions.reward = reward; + // mConditions.setupTime = cTime; + // mConditions.priority = priority; + // mConditions.provider = provider; + // mConditions.dir = signalBox.dir; + // mConditions.signalBox = signalBox; + // mConditions.amountPercent = amountPercent; + // } + + // // + // signalBox.Clean(); + // hasSignalBox = false; + } + + // + UpdateTo(cTime); + + // + // Draw Working Zone ... + if (hasWorkingZone) + { + // + workingZone.Draw( + drawer, + true, // Draw Waiting Zones ... + true, // Draw Inside Zones ... + true, // Draw Breaked Zones ... + true, // Draw Supply Zone ... + true, // Draw Demand Zone ... + false, // Draw Supply Zones ... + false, // Draw Demand Zones ... + false, // Draw Support Zones ... + false // Draw Resistance Zones ... + ); + + // + // XCBaseObject *objects[]; + // drawer.DrawState( + // decisionState, + // objects, + // false, // DrawT icksZone ... + // true, // Ignore SwingHighs ... + // true, // Ignore SwingLows ... + // true, // Ignore SupportZones ... + // true, // Ignore ResistanceZones ... + // true, // Ignore SupplyZones ... + // true, // Ignore DemandZones ... + // true, // Ignore BullishOrderBlocks ... + // true, // Ignore BearishOrderBlocks ... + // true, // Ignore BullishFairValueGaps ... + // true, // Ignore BearishFairValueGaps ... + // true, // Ignore BullishRejectionBars ... + // true, // Ignore BearishRejectionBars ... + // true, // Ignore BullishMomentumBars ... + // true, // Ignore BearishMomentumBars ... + // true, // Ignore BullishConsolidationZones ... + // true // Ignore BearishConsolidationZones ... + // ); + + // // + // int count = 0; + // bool has = false; + + // // + // has = workingZone.HasSupplyZones(); + // if (has) + // { + // } + + // // + // has = workingZone.HasDemandZones(); + // if (has) + // { + // // + // count = workingZone.CountDemandZones(); + // for (int i = 0; i < count; i++) + // { + // // + // XCDemandZone *iZone = workingZone.demandZones[i]; + + // // + // XCDemandZoneObject *iObj; + // bool isCreated = drawer.CreateDemandZone( + // iZone, + // iObj // + // ); + // } + // } + + // // + // Print(""); + } + + // + // Cleanup Resources ... + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + consolidationZBar.Clean(); + + // + return result; + } + + // + // Detect Trigger Conditions ... + bool DetectSignalTrigger( + // + X121SMCStrategyXWZSignalConditions &conditions, + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 + // + ) + { + // + bool result = false; + + // + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + return result; + } + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + // Cleanup ... + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + + // + double iAtr = decisionXConditions.atrBuffer[1]; + iAtr *= 1.5; + + // + // Check Signal Validation ... + // IMPORTANT: since all Validations done in SetUp Process ... + // here we only Execute Signal ... + + // + result = isBullish || + isBearish; + + // + if (result) + { + // + // Retrieve Entry Price ... + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Select and Apply SL ... + + // + double slsMin = GetMin(conditions.sls); + double slsMax = GetMax(conditions.sls); + + // + double longSL = slsMin; + double shortSL = slsMax; + + // + double sl = isBullish + ? longSL + : shortSL; + + // + conditions.sl = sl; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + } + + // + // Cleanup ... + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionState.Clean(); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseState.Clean(); + analyseConditions.Clean(); + analyseXConditions.Clean(); + + // + return result; + } + + // + // Detect Guards ... + bool DetectGuards( + // + X121SMCGuard &guards[], + const XPosition &positions[], + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // + ) + { + // + bool result = false; + return false; + + // + Clean(guards); + + // + bool isCycleHelpersValid = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + + // + // Set Provider for Common Guards ... + string provider = ToString(X_121_SMC_PROVIDER_XWZ); + + // + // Check Cycle Helpers Validation ... + result = isCycleHelpersValid; + if (!result) + { + return result; + } + + // + // Select Own Positions ... + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + provider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + // Check Extracted Positions ... + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + // Validate Own Positions ... + result = IsValidSize(count); + if (!result) + { + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + return result; + } + + // + // + // + + // + // Get Global and Common Guards ... + + // + ENUM_X_121_SMC_GUARD_ACTIONS ignoreGuards[1] = { + X_121_SMC_GUARD_ACTION_TRAIL_STOP // + }; + result = DetectX121SMCGuards( + provider, + guards, + positions, + decisionCycleHelper, + analyseCycleHelper, + consolidationCycleHelper, + visionCycleHelper, + // + ignoreGuards + // + ); + + // + // + // + + // + // Implement Custom Implemented Guards ... + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Detect Required Data for Analyse Market to Guard Positions ... + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + consolidationConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + consolidationConditions.Clean(); + + // + Clean(visionPoiEvents); + Clean(visionCycleEvents); + + // + visionConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Cycles POI States ... + XPOIState visionState = visionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState consolidationState = consolidationConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions visionXConditions = visionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + + // + // + // + + // + // Selected Consolidation Zones ... + + // + int idx = -1; + bool has = false; + + // + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + has = decisionState.HasBullishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(decisionState.bullishConsolidationZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + bullishConsolidationZone = decisionState.bullishConsolidationZones[idx]; + } + } + + // + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + has = decisionState.HasBearishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(decisionState.bearishConsolidationZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + bearishConsolidationZone = decisionState.bearishConsolidationZones[idx]; + } + } + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Available Guards: + // X_121_SMC_GUARD_ACTION_NONE + // X_121_SMC_GUARD_ACTION_CLOSE + // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // X_121_SMC_GUARD_ACTION_HEDGE + + // + // X_121_SMC_GUARD_ACTION_CLOSE: + // Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // Close All Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // Close All Long Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // Close All Short Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // Partial Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // Trail Stop Specified Position on Specified Conditions ... + bool handleStoptrailingBasedOnConsolidationZones = true; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + bool isLong = IsLong(iPosition.type); + bool isInProfit = iPosition.profit > 0; + + // + double sl = iPosition.sl; + double tp = iPosition.tp; + + // + // Trail Stops Using Consolidation Zones ... + + // + bool canTraiLonglUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (isLong && + isInProfit && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > iPosition.sl && + bullishConsolidationZone.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingCZone) + { + sl = bullishConsolidationZone.lower; + } + + // + bool canTraiShortlUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (!isLong && + isInProfit && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < iPosition.sl && + bearishConsolidationZone.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingCZone) + { + sl = bearishConsolidationZone.upper; + } + + // + bool canTrailUsingCZone = + canTraiLonglUsingCZone || + canTraiShortlUsingCZone; + + // + bool isSLPassed = + sl > 0 && + (isLong + ? iPosition.price - sl >= points * 15 + : sl - iPosition.price >= points * 15); + + // + bool canTrail = + isSLPassed && + canTrailUsingCZone; + if (canTrail) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.ticket = iPosition.ticket; + + // + iGuard.sl = sl; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // Trail Target Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_HEDGE: + // Hedge all Positions on Specified Conditions ... + + // + // Cleanup Collections ... + + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + // + // Add Conditions to Conditions Collection ... + int AddConditionsIfNotExists( + int maxAllowed = 10 // + ) + { + // + int result = 0; + + // + bool isSetuped = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(mConditionsCollection); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXWZSignalConditions tmpItems[]; + Copy( + mConditionsCollection, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(mConditions.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXWZSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = mConditions.dir == iItem.dir && + mConditions.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + mConditionsCollection, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + mConditions, + mConditionsCollection // + ); + + // + // Remove Olds ... + CleanupArray( + mConditionsCollection, + maxAllowed // + ); + + // + result = ArraySize(mConditionsCollection); + + // + return result; + } + + // + // Draw Functions ... + // + + // + void DrawBar( + XOHCL &bar, + XCPOIDrawer *drawer, + bool forceClean = true // + ) + { + // + if (forceClean) + { + mBarObjects.Clear(); + } + + // + if (drawer == NULL || + !bar.IsValid()) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + + // + int widthBar = 2; + bool fillShadowsBar = true; + ENUM_LINE_STYLE styleBar = STYLE_SOLID; + color clrBar = + isBullish + ? clrAqua + : clrMagenta; + + // + datetime to = bar.NextAt(); + + // + XCOHCLObject *iObj; + bool isCreated = drawer + .CreateBar( + bar, + iObj, + to // + ); + if (isCreated) + { + // + iObj.BarSpes( + widthBar, + clrBar, + styleBar // + ); + + // + iObj.LowShadowFill(fillShadowsBar); + iObj.HighShadowFill(fillShadowsBar); + + // + mBarObjects.Add(iObj); + } + } + + // + protected: + // + + // + private: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + CArrayObj mObjects; + CArrayObj mBarObjects; + CArrayObj mWorkingZoneObjects; + + /** + * Initialize ... + */ + void Init() + { + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + mConditions.Clean(); + workingZone.Clean(); + Clean(mConditionsCollection); + + // + mBarObjects.Clear(); + } + + /** + * Update To Time of Exists Components ... + * + * @param value: updated time ... + */ + void UpdateTo( + datetime value = NULL // + ) + { + // + value = NormalizeTime(value); + + // + workingZone.UpdateTo(value); + } + + // + // Helpers ... + + // + bool CalculateRiskReward( + ENUM_X121SMC_XWZ_PRIORITY priority, + double &reward, + double &amountPercent // + ) + { + // + bool result = false; + + // + reward = 0; + amountPercent = 0; + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE; + if (!result) + { + return result; + } + + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + reward = 6; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + reward = 4; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + reward = 3; + amountPercent = 1.5; + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + reward = 2; + amountPercent = 1; + break; + + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + reward = 1; + amountPercent = 0.5; + break; + } + + // + result = + // + reward > 0 && + amountPercent > 0 + // + ; + + // + return result; + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class.mq5 new file mode 100644 index 0000000..c80b6cc --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.class.mq5 @@ -0,0 +1,3960 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "./x-121.smc.xwz.signal.lib.mq5" + +// +// Definition ... +class XCX121SMCXWZSignalDetector : public XCBase +{ + // + public: + // + // Props ... + XOBFVG chochZone; + XOBFVG targetZone; + XOBFVG signalZone; + XOBFVG waitingZone; + X121SMCStrategyXWZWorkingZone workingZone; + X121SMCStrategyXWZSignalConditions mConditions; + X121SMCStrategyXWZSignalConditions mConditionsCollection[]; + + // + // Constructor(s) ... + XCX121SMCXWZSignalDetector( + string _symbol, + ENUM_TIMEFRAMES _period // + ) + { + // + symbol = _symbol; + period = _period; + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCXWZSignalDetector() + { + DeInit(); + } + + // + // + // + + // + // Detect Setup Conditions ... + bool DetectSignalSetup( + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + // + mConditions.Clean(); + + // + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + mConditions.symbol = symbol; + mConditions.period = period; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + double pivot = 0; + double point = 0; + double target = 0; + double reward = 0; + double amountPercent = 0; + ENUM_X121SMC_XWZ_PRIORITY priority = X121SMC_XWZ_PRIORITY_NONE; + + // + // Cycles Conditions ... + + // + XOHCL consolidationZBar; + result = consolidationCycleHelper.GetBar( + consolidationZBar, + zIndex // + ); + if (!result) + { + // + consolidationZBar.Clean(); + return result; + } + + // + bool drawBar = true; + if (drawBar) + { + // + DrawBar( + consolidationZBar, + decisionCycleHelper.mPOIDrawer // + ); + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Choch Trading Senario ... + bool hasChochBullishConditions = false; + bool hasChochBearishConditions = false; + + // + // Order Flow Side Trading Senario ... + bool hasOrderFlowhBullishConditions = false; + bool hasOrderFlowhBearishConditions = false; + + // + // Trend Line Trading Senario ... + bool hasTrendLineBullishConditions = false; + bool hasTrendLineBearishConditions = false; + + // + // Quarter Line Trading Senario ... + bool hasBQuarterLineBullishConditions = false; + bool hasBQuarterLineBearishConditions = false; + + // + // Supply and Demand Trading Senario ... + bool hasSupDemBullishConditions = false; + bool hasSupDemBearishConditions = false; + + // + // Support and Resistance Trading Senario ... + bool hasSupResBullishConditions = false; + bool hasSupResBearishConditions = false; + + // + ENUM_X121SMC_XWZ_PROVIDERS provider = X121SMC_XWZ_PROVIDER_NONE; + + // + // Detect Working Zone ... + bool hasWorkingZone = workingZone.IsValid(); + if (!hasWorkingZone) + { + hasWorkingZone = DetectWorkingZone(visionState); + } + + // + // result = hasWorkingZone; + // if (!result) + // { + // // + // Clean(visionPoiEvents); + // Clean(analysePoiEvents); + // Clean(decisionPoiEvents); + // Clean(consolidationPoiEvents); + + // // + // Clean(visionCycleEvents); + // Clean(analyseCycleEvents); + // Clean(decisionCycleEvents); + // Clean(consolidationCycleEvents); + + // // + // visionState.Clean(); + // analyseState.Clean(); + // decisionState.Clean(); + // consolidationState.Clean(); + + // // + // visionConditions.Clean(); + // analyseConditions.Clean(); + // decisionConditions.Clean(); + // consolidationConditions.Clean(); + + // // + // visionXConditions.Clean(); + // analyseXConditions.Clean(); + // decisionXConditions.Clean(); + // consolidationXConditions.Clean(); + + // // + // mConditions.Clean(); + // consolidationZBar.Clean(); + + // // + // return result; + // } + + // + // Supply Zones ... + bool hasSupplyZones = workingZone.HasSupplyZones(); + int supplyZonesCount = workingZone.CountSupplyZones(); + if (hasWorkingZone) + { + // + supplyZonesCount = workingZone + .DetectSupplyZones(consolidationState); + hasSupplyZones = IsValidSize(supplyZonesCount); + } + + // + // Demand Zones ... + bool hasDemandZones = workingZone.HasDemandZones(); + int demandZonesCount = workingZone.CountDemandZones(); + if (hasWorkingZone) + { + // + demandZonesCount = workingZone + .DetectDemandZones(consolidationState); + hasDemandZones = IsValidSize(demandZonesCount); + } + + // + // TODO: Remove this ... + UpdateTo(cTime); + + // + // Detect Working Zone Destroy ... + bool isWorkingZoneDetroyed = + hasWorkingZone && + workingZone.IsDestroyed(); + if (isWorkingZoneDetroyed) + { + mWorkingZoneObjects.Clear(); + } + + // + // result = !isWorkingZoneDetroyed; + // if (!result) + // { + // // + // workingZone.Clean(); + // mWorkingZoneObjects.Clear(); + + // // + // Clean(visionPoiEvents); + // Clean(analysePoiEvents); + // Clean(decisionPoiEvents); + // Clean(consolidationPoiEvents); + + // // + // Clean(visionCycleEvents); + // Clean(analyseCycleEvents); + // Clean(decisionCycleEvents); + // Clean(consolidationCycleEvents); + + // // + // visionState.Clean(); + // analyseState.Clean(); + // decisionState.Clean(); + // consolidationState.Clean(); + + // // + // visionConditions.Clean(); + // analyseConditions.Clean(); + // decisionConditions.Clean(); + // consolidationConditions.Clean(); + + // // + // visionXConditions.Clean(); + // analyseXConditions.Clean(); + // decisionXConditions.Clean(); + // consolidationXConditions.Clean(); + + // // + // mConditions.Clean(); + // consolidationZBar.Clean(); + + // // + // return result; + // } + + // + // Checking Target Zone Breaked ... + bool hasTargetZone = targetZone.IsValid(); + if (hasTargetZone) + { + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + zIndex // + ); + + XOHCL cBar; + isInited = + isInited && + bar.GetPreviousBar(cBar); + + // + bool isBullish = targetZone.IsBullish(); + + // + bool isLowerBreaked = + // + bar.high < targetZone.ob.Lower() && + cBar.high < targetZone.ob.Lower() + // + ; + + // + bool isUpperBreaked = + // + bar.low > targetZone.ob.Upper() && + cBar.low > targetZone.ob.Upper() + // + ; + + // + bool isBreaked = isBullish + ? isLowerBreaked + : isUpperBreaked; + if (isBreaked) + { + // + mWorkingZoneObjects.Clear(); + targetZone.Clean(); + } + } + + // + // Detect Order Flow ... + ENUM_X_DIRECTION trend = X_DIRECTION_NONE; + bool hasOrderFlow = + hasWorkingZone && + workingZone.HasOrderFlow(trend); + if (!hasOrderFlow) + { + // + int orderFlowCount = workingZone.DetectOrderFlow( + symbol, + period, + trend, + visionState, + consolidationState, + analyseState, + decisionState // + ); + hasOrderFlow = IsValidSize(orderFlowCount); + } + + // + bool hasTrend = HasDirection(trend); + bool hasBllishTrend = + hasTrend && + IsBullish(trend); + bool hasBearishTrend = + hasTrend && + IsBearish(trend); + + // + UpdateTo(cTime); + + // + isBullish = IsBullish(trend); + isBearish = IsBearish(trend); + + // + bool hasPriority = workingZone + .DetectPriority( + priority, + trend, + zIndex, + period // + ); + + // + bool hasRewardAmount = CalculateRiskReward( + priority, + reward, + amountPercent // + ); + + // + // Checking Order Flow Break ... + int breakedIDX = -1; + bool isOrderFlowBreaked = + hasOrderFlow && + hasWorkingZone && + workingZone.IsOrderFlowBreaked( + breakedIDX, + true, // Force OB Breaked + false, // Force FVG Breaked + zIndex, + period // + ); + + // + // Order Flow Breaked Senario ... + if (isOrderFlowBreaked) + { + // + AddRef( + workingZone.orderFlow[breakedIDX], + workingZone.brokenOrderFlow // + ); + + // + signalZone = workingZone.orderFlow[breakedIDX]; + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH; + + // + ArrayRemove( + workingZone.orderFlow, + breakedIDX, + 1 // + ); + Clean(workingZone.orderFlow); + + // + CleanupArray( + workingZone.brokenOrderFlow, + 10 // + ); + } + + // + // First Check Last Order Flow FVG ... + XOBFVG youngestOrderFlow; + int youngestOBFVGIDX = GetYoungest(workingZone.orderFlow); + bool hasYoungestOBFVG = IsValidIndex(youngestOBFVGIDX); + if (hasYoungestOBFVG) + { + // + youngestOrderFlow = workingZone.orderFlow[youngestOBFVGIDX]; + + // + XOHCL obWorkerBar; + XOHCL obActivationBar; + + // + XOHCL fvgWorkerBar; + XOHCL fvgActivationBar; + + // + bool isOBBodyOut = false; + bool isOBWorked = youngestOrderFlow + .ob + .IsWorked( + trend, + obWorkerBar, + isOBBodyOut, + false // + ); + + // + bool isOBBodyIn = false; + bool isOBActivated = youngestOrderFlow + .ob + .IsActivated( + trend, + obActivationBar, + isOBBodyIn, + false // + ); + + // + bool isFVGBodyOut = false; + bool isFVGWorked = youngestOrderFlow + .fvg + .IsWorked( + trend, + fvgWorkerBar, + isFVGBodyOut, + false // + ); + + // + bool isFVGBodyIn = false; + bool isFVGActivated = youngestOrderFlow + .fvg + .IsActivated( + trend, + fvgActivationBar, + isFVGBodyIn, + false // + ); + + // + if (!isFVGWorked && + isFVGActivated) + { + // + youngestOrderFlow + .UpdateZones(decisionState); + + // + signalZone = youngestOrderFlow; + youngestOrderFlow.Clean(); + ArrayRemove( + workingZone.orderFlow, + youngestOBFVGIDX, + 1 // + ); + + // + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE; + } + else + { + // + bool isPriceInsideFVG = + // + IsInside( + consolidationZBar.high, + youngestOrderFlow.fvg // + ) + // + && + // + IsInside( + consolidationZBar.low, + youngestOrderFlow.fvg // + ) + // + ; + + // + if (isPriceInsideFVG) + { + // + youngestOrderFlow + .UpdateZones(decisionState); + + // + signalZone = youngestOrderFlow; + youngestOrderFlow.Clean(); + ArrayRemove( + workingZone.orderFlow, + youngestOBFVGIDX, + 1 // + ); + + // + provider = X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE; + } + } + + // + fvgWorkerBar.Clean(); + fvgActivationBar.Clean(); + } + + // + // Check New Order Blocks ... + bool hasNewConsolidationBullishOB = Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + consolidationPoiEvents // + ); + bool hasNewConsolidationBearishOB = Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + consolidationPoiEvents // + ); + bool hasNewOB = hasNewConsolidationBullishOB || + hasNewConsolidationBearishOB; + + // + // Check New Fair Value Gaps ... + bool hasNewConsolidationBullishFVG = Contains( + X_BULLISH_FVG_DETECTED, + consolidationPoiEvents // + ); + bool hasNewConsolidationBearishFVG = Contains( + X_BEARISH_FVG_DETECTED, + consolidationPoiEvents // + ); + bool hasNewFVG = hasNewConsolidationBullishFVG || + hasNewConsolidationBearishFVG; + + // + // Check New Order Blocks ... + bool hasNewAnalyseBullishOrderBlock = Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + analysePoiEvents // + ); + bool hasNewAnalyseBearishOrderBlock = Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + analysePoiEvents // + ); + bool hasNewAnalyseOB = hasNewAnalyseBullishOrderBlock || + hasNewAnalyseBearishOrderBlock; + + // + // Check New Fair Value Gaps ... + bool hasNewAnalyseBullishFVG = Contains( + X_BULLISH_FVG_DETECTED, + analysePoiEvents // + ); + bool hasNewAnalyseBearishFVG = Contains( + X_BEARISH_FVG_DETECTED, + analysePoiEvents // + ); + bool hasNewAnalyseFVG = hasNewAnalyseBullishFVG || + hasNewAnalyseBearishFVG; + + // + // Do Order Flow Actions when new Order Blocks + // or FVGs Formed ... + if (hasNewOB || + hasNewFVG || + hasNewAnalyseOB || + hasNewAnalyseFVG) + { + // + XCFVG *newFVG = NULL; + XCOrderBlock *newOB = NULL; + XCFVG *newAnalyseFVG = NULL; + XCOrderBlock *newAnalyseOB = NULL; + + // + bool isValid = false; + bool hasWaitingZone = waitingZone.IsValid(); + + // + int idx = -1; + if (hasNewOB) + { + // + if (hasNewConsolidationBullishOB) + { + // + idx = consolidationState.CountBullishOrderBlocks() - 1; + newOB = consolidationState.bullishOrderBlocks[idx]; + } + else + { + // + idx = consolidationState.CountBearishOrderBlocks() - 1; + newOB = consolidationState.bearishOrderBlocks[idx]; + } + + // + if (hasWaitingZone) + { + } + else + { + // + isValid = + !waitingZone.HasOB() + ? true + : !IsSame( + newOB, + waitingZone.ob // + ); + if (isValid) + { + // + bool isAbove = IsAbove( + newOB, + youngestOrderFlow.ob, + true // Ignore Inside ... + ); + bool isBelow = IsBelow( + newOB, + youngestOrderFlow.ob, + true // Ignore Inside ... + ); + + // + isValid = + isBullish + ? isAbove + : isBelow; + + // + if (isValid) + { + waitingZone.ob = newOB; + } + } + } + } + + // + if (hasNewFVG) + { + // + if (hasNewConsolidationBullishFVG) + { + // + idx = consolidationState.CountBullishFairValueGaps() - 1; + newFVG = consolidationState.bullishFairValueGaps[idx]; + } + else + { + // + idx = consolidationState.CountBearishFairValueGaps() - 1; + newFVG = consolidationState.bearishFairValueGaps[idx]; + } + } + + // + if (hasNewAnalyseOB) + { + // + if (hasNewAnalyseBullishOrderBlock) + { + // + idx = analyseState.CountBullishOrderBlocks() - 1; + newAnalyseOB = analyseState.bullishOrderBlocks[idx]; + } + else + { + // + idx = analyseState.CountBearishOrderBlocks() - 1; + newAnalyseOB = analyseState.bearishOrderBlocks[idx]; + } + } + + // + if (hasNewAnalyseFVG) + { + // + if (hasNewAnalyseBullishFVG) + { + // + idx = analyseState.CountBullishFairValueGaps() - 1; + newAnalyseFVG = analyseState.bullishFairValueGaps[idx]; + } + else + { + // + idx = analyseState.CountBearishFairValueGaps() - 1; + newAnalyseFVG = analyseState.bearishFairValueGaps[idx]; + } + + // + if (hasWaitingZone) + { + } + else + { + // + if (waitingZone.HasOB()) + { + // + XCFVG *tmpFVGs[]; + XCFVG *tmpWorkingFVGs[]; + bool isOBBullish = waitingZone.ob.IsBullish(); + if (isOBBullish) + { + Copy( + analyseState.bullishFairValueGaps, + tmpFVGs // + ); + } + else + { + Copy( + analyseState.bearishFairValueGaps, + tmpFVGs // + ); + } + + // + for (int j = 0; j < ArraySize(tmpFVGs); j++) + { + // + XCFVG *jFVG = tmpFVGs[j]; + + // + // Check Start Date ... + bool isFromPassed = jFVG.From() > waitingZone.ob.From(); + if (!isFromPassed) + { + // + ZeroMemory(jFVG); + continue; + } + + // + // Check Place ... + + // + bool isAbove = IsAboveDiff( + jFVG, + waitingZone.ob, + true // + ); + + // + bool isBelow = IsBelowDiff( + jFVG, + waitingZone.ob, + true // + ); + + // + bool isInside = IsInsideDiff( + jFVG, + waitingZone.ob, + false // + ); + + // + bool isPlacePassed = + isInside || + (isBullish + ? isAbove + : isBelow); + if (!isPlacePassed) + { + // + ZeroMemory(jFVG); + continue; + } + + // + Add( + jFVG, + tmpWorkingFVGs // + ); + } + + // + int fvgsCount = ArraySize(tmpWorkingFVGs); + isValid = IsValidSize(fvgsCount); + if (isValid) + { + // + idx = + isBullish + ? GetLowest(tmpWorkingFVGs) + : GetHighest(tmpWorkingFVGs); + + // + if (IsValidIndex(idx)) + { + // + XCFVG *selectedFVG = tmpWorkingFVGs[idx]; + + // + waitingZone.fvg = selectedFVG; + + // + bool isExists = FindIndex( + idx, + selectedFVG, + tmpFVGs // + ); + if (isExists) + { + // + ArrayRemove( + tmpFVGs, + idx, + 1 // + ); + } + } + } + + // + Clean(tmpFVGs); + Clean(tmpWorkingFVGs); + } + } + } + + // + hasWaitingZone = waitingZone.IsValid(); + if (hasWaitingZone) + { + // + bool isSameDir = waitingZone.GetDirection() == trend; + if (!isSameDir) + { + targetZone = waitingZone; + } + else + { + workingZone.AddOrderFlowItem(waitingZone); + } + + // + waitingZone.Clean(); + } + + // + if (signalZone.IsValid() && + provider == X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH) + { + // + ENUM_X_DIRECTION iForDir = Opposit(signalZone.GetDirection()); + if (hasNewAnalyseOB && + hasNewAnalyseFVG) + { + // + bool isSameDir = + newAnalyseOB.GetDirection() == iForDir && + newAnalyseFVG.GetDirection() == iForDir; + bool isOneInsideAnoter = + // + (newAnalyseFVG.Upper() < newAnalyseOB.Upper() && + newAnalyseFVG.Upper() > newAnalyseOB.Lower()) + // + || + // + (newAnalyseOB.Upper() < newAnalyseFVG.Upper() && + newAnalyseOB.Upper() > newAnalyseFVG.Lower()) + // + ; + + // + bool isZoneDetected = + isSameDir && + isOneInsideAnoter; + if (isZoneDetected) + { + // + XOBFVG iSignalZone; + iSignalZone.ob = newAnalyseOB; + iSignalZone.fvg = newAnalyseFVG; + + // + chochZone = iSignalZone; + } + } + } + + // + ZeroMemory(newOB); + ZeroMemory(newFVG); + ZeroMemory(newAnalyseOB); + ZeroMemory(newAnalyseFVG); + } + + // + bool isPriceInsideCHOCHZone = false; + bool hasCHOCHZone = chochZone.IsValid(); + if (hasCHOCHZone) + { + // + XOHCL cBar; + bool isInited = cBar.Init( + symbol, + period, + cIndex // + ); + + // + isPriceInsideCHOCHZone = + isInited && + cBar.low >= chochZone.fvg.Lower() && + cBar.high <= chochZone.fvg.Upper(); + if (isPriceInsideCHOCHZone) + { + // + // Reverse Trend and ReCalculate Requirements + // For CHOCH Tradng ... + + // + trend = chochZone.GetDirection(); + + // + isBullish = IsBullish(trend); + isBearish = IsBearish(trend); + + // + bool hasPriority = workingZone + .DetectPriority( + priority, + trend, + zIndex, + period // + ); + + // + bool hasRewardAmount = CalculateRiskReward( + priority, + reward, + amountPercent // + ); + + // + provider = X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH; + } + + // + cBar.Clean(); + } + + // + // + // + + // + if (hasSupplyZones || + hasDemandZones) + { + // + UpdateTo(cTime); + DrawWorkingZone( + visionCycleHelper.mPOIDrawer // + ); + Print("CHECK ..."); + } + + // + // Reading Trand Line Value ... + double zValue = workingZone.GetOrderFlowTrendLinePrice( + zIndex, + period // + ); + double cValue = workingZone.GetOrderFlowTrendLinePrice( + cIndex, + period // + ); + double pValue = workingZone.GetOrderFlowTrendLinePrice( + pIndex, + period // + ); + double ppValue = workingZone.GetOrderFlowTrendLinePrice( + ppIndex, + period // + ); + + // + // Implementing Signals ... + // + + // + // TODO: Implement Order Flow Side Trading Senario ... + bool hasOrderFlowConditions = + hasTrend && + hasPriority && + hasRewardAmount && + signalZone.IsValid() && + provider == X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE; + + // + hasOrderFlowhBullishConditions = + isBullish && + hasOrderFlowConditions && + signalZone.IsBullish(); + + // + hasOrderFlowhBearishConditions = + isBearish && + hasOrderFlowConditions && + signalZone.IsBearish(); + + // + if (hasOrderFlowConditions) + { + // + mConditions.signalZone = signalZone; + + // + point = hasOrderFlowhBullishConditions + ? signalZone.ob.Upper() + : signalZone.ob.Lower(); + + // + pivot = hasOrderFlowhBullishConditions + ? signalZone.ob.Lower() + : signalZone.ob.Upper(); + + // + signalZone.Clean(); + } + + // + // TODO: Implement Inside Zone Trading Senario ... + bool hasInsideZoneConditions = + hasTrend && + hasPriority && + hasRewardAmount && + signalZone.IsValid() && + provider == X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE; + + // + bool hasInsideZoneBullishConditions = + isBullish && + signalZone.IsBullish() && + hasInsideZoneConditions; + + // + bool hasInsideZoneBearishConditions = + isBearish && + signalZone.IsBearish() && + hasInsideZoneConditions; + + // + if (hasInsideZoneConditions) + { + // + mConditions.signalZone = signalZone; + + // + point = hasOrderFlowhBullishConditions + ? signalZone.ob.Upper() + : signalZone.ob.Lower(); + + // + pivot = hasOrderFlowhBullishConditions + ? signalZone.ob.Lower() + : signalZone.ob.Upper(); + + // + signalZone.Clean(); + } + + // + // TODO: Implement CHOCH Trading Senario ... + bool hasCHOCHConditions = + hasCHOCHZone && + chochZone.IsValid() && + isPriceInsideCHOCHZone && + provider == X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH; + + // + hasChochBullishConditions = + hasCHOCHConditions && + chochZone.IsBullish(); + hasChochBearishConditions = + hasCHOCHConditions && + chochZone.IsBearish(); + + // + if (hasCHOCHConditions) + { + // + mConditions.signalZone = chochZone; + + // + point = hasChochBullishConditions + ? chochZone.ob.Upper() + : chochZone.ob.Lower(); + + // + pivot = hasChochBearishConditions + ? chochZone.ob.Lower() + : chochZone.ob.Upper(); + + // + chochZone.Clean(); + signalZone.Clean(); + } + + // + // TODO: Implement Trend Line Trading Senario ... + + // + // TODO: Implement Quarter Line Trading Senario ... + + // + // TODO: Implement Supply and Demand Trading Senario ... + + // + // TODO: Implement Support and Resistance Trading Senario ... + + // + // TODO: Implement Mitigation Blocks Trading Senario ... + + // + // Summarize ... + + // + bool hasBullishConditions = + // + hasChochBullishConditions || + hasSupDemBullishConditions || + hasSupResBullishConditions || + hasTrendLineBullishConditions || + hasOrderFlowhBullishConditions || + hasInsideZoneBullishConditions || + hasBQuarterLineBullishConditions + // + ; + + // + bool hasBearishConditions = + // + hasChochBearishConditions || + hasSupDemBearishConditions || + hasSupResBearishConditions || + hasTrendLineBearishConditions || + hasOrderFlowhBearishConditions || + hasInsideZoneBearishConditions || + hasBQuarterLineBearishConditions + // + ; + + // + result = + hasBullishConditions || + hasBearishConditions; + + // + if (result) + { + // + mConditions.dir = trend; + mConditions.pivot = pivot; + mConditions.point = point; + mConditions.reward = reward; + mConditions.setupTime = cTime; + mConditions.priority = priority; + mConditions.provider = provider; + mConditions.amountPercent = amountPercent; + } + + // + // Cleanups ... + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + consolidationState.Clean(); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + visionXConditions.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationXConditions.Clean(); + + // + // mConditions.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Detect Trigger Conditions ... + bool DetectSignalTrigger( + // + X121SMCStrategyXWZSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 + // + ) + { + // + bool result = false; + + // + result = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + if (!result) + { + return result; + } + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + double sls[]; + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + // Cleanup ... + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + + // + // Check Signal Validation ... + + // + XOHCL cBar; + bool isInited = cBar.Init( + conditions.symbol, + conditions.period, + cIndex // + ); + XOHCL pBar; + isInited = + isInited && + cBar.GetPreviousBar(pBar); + bool isLowerBreaked = + // + isInited && + cBar.high < conditions.point && + pBar.high >= conditions.point + // + ; + bool isUpperBreaked = + // + isInited && + cBar.low > conditions.point && + pBar.low <= conditions.point + // + ; + bool isZoneBreaked = + (isBullish && + isLowerBreaked) || + (isBearish && + isUpperBreaked); + result = !isZoneBreaked; + if (!result) + { + // + cBar.Clean(); + pBar.Clean(); + conditions.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionState.Clean(); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseState.Clean(); + analyseConditions.Clean(); + analyseXConditions.Clean(); + } + + // + cBar.Clean(); + pBar.Clean(); + + // + double bullishScore = 0; + double bearishScore = 0; + decisionXConditions.GenerateScore( + bullishScore, + bearishScore // + ); + bool isBullishScorePassed = + isBullish && + bullishScore > (bearishScore * 1.5); + bool isBearishScorePassed = + isBearish && + bearishScore > (bullishScore * 1.5); + bool isScorePassed = isBullishScorePassed || + isBearishScorePassed; + + // + // Base SL Used Pivot of Conditions ... + // Add( + // conditions.pivot, + // sls // + // ); + + // + int lowestSupportIDX = -1; + int highestResistanceIDX = -1; + bool isSupportRejected = false; + bool isResistanceRejected = false; + bool hasSignalZone = conditions.signalZone.IsValid(); + if (hasSignalZone) + { + // + conditions + .signalZone + .UpdateZones(decisionState); + conditions + .signalZone + .UpdateTo(cTime); + + // + XOHCL cBar; + bool isBarInited = cBar.Init( + conditions.symbol, + conditions.period, + cIndex // + ); + + // + lowestSupportIDX = GetLowest(conditions.signalZone.supportZones); + if (IsValidIndex(lowestSupportIDX)) + { + // + isSupportRejected = + // + isBarInited && + ( + // + (cBar.low < conditions.signalZone.supportZones[lowestSupportIDX].Upper() && + cBar.GetDown() > conditions.signalZone.supportZones[lowestSupportIDX].Upper()) + // + || + // + (cBar.low < conditions.signalZone.supportZones[lowestSupportIDX].Lower() && + cBar.GetDown() > conditions.signalZone.supportZones[lowestSupportIDX].Lower()) + // + ) + // + ; + + // + isSupportRejected = + isBullish && + isSupportRejected; + if (isSupportRejected) + { + // + double vPivot = conditions.signalZone.supportZones[lowestSupportIDX].Lower(); + bool canSetPivot = vPivot > conditions.pivot && + vPivot < conditions.point; + if (canSetPivot) + { + // + Add( + vPivot, + sls // + ); + } + } + } + + // + highestResistanceIDX = GetHighest(conditions.signalZone.resistanceZones); + if (IsValidIndex(highestResistanceIDX)) + { + // + isResistanceRejected = + // + isBarInited && + ( + // + (cBar.high > conditions.signalZone.resistanceZones[highestResistanceIDX].Upper() && + cBar.GetUp() < conditions.signalZone.resistanceZones[highestResistanceIDX].Upper()) + // + || + // + (cBar.high > conditions.signalZone.resistanceZones[highestResistanceIDX].Lower() && + cBar.GetUp() < conditions.signalZone.resistanceZones[highestResistanceIDX].Lower()) + // + ) + // + ; + + // + isResistanceRejected = + isBearish && + isResistanceRejected; + if (isResistanceRejected) + { + // + double vPivot = conditions.signalZone.resistanceZones[highestResistanceIDX].Upper(); + bool canSetPivot = vPivot < conditions.pivot && + vPivot > conditions.point; + if (canSetPivot) + { + // + Add( + vPivot, + sls // + ); + } + } + } + + // + cBar.Clean(); + } + + // + // Consolidation Zone Detection ... + + // + // Detect Consolidation Zones ... + + // + // Bullish Consolidation Zone ... + XConsolidationZone bullishCZones[]; + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + int bullishCZonesCount = decisionCycleHelper.FillConsolidationZones( + X_DIRECTION_BULLISH, + bullishCZones // + ); + bool hasBullishConsolidationZones = IsValidSize(bullishCZonesCount); + if (hasBullishConsolidationZones) + { + // + int idx = -1; + while (HasChild(bullishCZones)) + { + // + idx = GetYoungest(bullishCZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + // + bullishConsolidationZone = bullishCZones[idx]; + + // + ArrayRemove( + bullishCZones, + idx, + 1 // + ); + + // + // Check Zone Based On pivot, since this is the SL ... + hasBullishConsolidationZone = + isBullish && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > conditions.pivot && + bullishConsolidationZone.upper <= conditions.point; + if (hasBullishConsolidationZone) + { + // + Add( + bullishConsolidationZone.lower, + sls // + ); + } + } + } + } + Clean(bullishCZones); + bullishConsolidationZone.Clean(); + + // + // Bearish Consolidation Zone ... + XConsolidationZone bearishCZones[]; + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + int bearishCZonesCount = decisionCycleHelper.FillConsolidationZones( + X_DIRECTION_BEARISH, + bearishCZones // + ); + bool hasBearishConsolidationZones = IsValidSize(bearishCZones); + if (hasBearishConsolidationZones) + { + // + int idx = -1; + while (HasChild(bearishCZones)) + { + // + idx = GetYoungest(bearishCZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + // + bearishConsolidationZone = bearishCZones[idx]; + + // + ArrayRemove( + bearishCZones, + idx, + 1 // + ); + + // + hasBearishConsolidationZone = + isBearish && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < conditions.pivot && + bearishConsolidationZone.lower >= conditions.point; + if (hasBearishConsolidationZone) + { + // + Add( + bearishConsolidationZone.upper, + sls // + ); + } + } + } + } + Clean(bearishCZones); + bearishConsolidationZone.Clean(); + + // + // Check VWap Crossing ... + + // + bool isVWapSwitchedToBullish = + // + (decisionXConditions.isVWapBullishOrdered && + decisionXConditions.isVWapSwitchedToBullishState) + // + || + // + (decisionXConditions.isVWapBullishState && + decisionXConditions.isVWapSwitchedToBullishOrdered) + // + ; + + // + isVWapSwitchedToBullish = + isBullish && + isVWapSwitchedToBullish; + if (isVWapSwitchedToBullish) + { + // + double vPivot = decisionXConditions.vwapMin; + bool canSetPivot = vPivot > conditions.pivot && + vPivot < conditions.point; + if (canSetPivot) + { + // + Add( + vPivot, + sls // + ); + } + } + + // + bool isVWapSwitchedToBearish = + // + (decisionXConditions.isVWapBearishOrdered && + decisionXConditions.isVWapSwitchedToBearishState) + // + || + // + (decisionXConditions.isVWapBearishState && + decisionXConditions.isVWapSwitchedToBearishOrdered) + // + ; + + // + isVWapSwitchedToBearish = + isBearish && + isVWapSwitchedToBearish; + if (isVWapSwitchedToBearish) + { + // + double vPivot = decisionXConditions.vwapMax; + bool canSetPivot = vPivot < conditions.pivot && + vPivot > conditions.point; + if (canSetPivot) + { + // + Add( + vPivot, + sls // + ); + } + } + + // + // Point Break ... + isInited = cBar.Init( + conditions.symbol, + conditions.period, + cIndex // + ); + double point = conditions.point; + bool isPointBreaked = + isInited && + IsBarBreak( + point, + setupDir, + cBar // + ); + cBar.Clean(); + + // + bool isCommonsPassed = + // + (isSupportRejected || + isResistanceRejected || + isVWapSwitchedToBullish || + isVWapSwitchedToBearish || + hasBullishConsolidationZone || + hasBearishConsolidationZone) + // + ; + + // + // Trigger Conditions ... + + // + bool canTriggerCHOCHZone = + // + isScorePassed && + isCommonsPassed && + conditions.provider == X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH + // + ; + + // + bool canTriggerActivatedZone = + // + // isPointBreaked && + isScorePassed && + isCommonsPassed && + conditions.provider == X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE + // + ; + + // + bool canTriggerPriceInsideZone = + // + isScorePassed && + isCommonsPassed && + conditions.provider == X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE + // + ; + + // + bool canTrigger = (canTriggerCHOCHZone || + canTriggerActivatedZone || + canTriggerPriceInsideZone); + + // + // Summary ... + + // + isBullish = + // + isBullish && + canTrigger + // + ; + + // + isBearish = + // + isBearish && + canTrigger + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup ... + + // + cBar.Clean(); + pBar.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionState.Clean(); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseState.Clean(); + analyseConditions.Clean(); + analyseXConditions.Clean(); + + // + return result; + } + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Manipulate SL Based on Consolidation Zones ... + + // + double iAtr = decisionXConditions.atrBuffer[1]; + iAtr *= 1.5; + + // + // Since Pivot Value almost used + // as Default SL, if there isn't any Refind SL + // we use Default ... + if (!HasChild(sls)) + { + // + Add( + conditions.pivot, + sls // + ); + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Checking Targets ... + + // + ENUM_X121SMC_XWZ_PRIORITY priority = X121SMC_XWZ_PRIORITY_NONE; + bool hasPriority = workingZone + .DetectPriority( + priority, + setupDir, + zIndex, + decisionState.period // + ); + + // + // Order Block Targets ... + + // + XCOrderBlock *bullishOBs[]; + Copy( + analyseState.bullishOrderBlocks, + bullishOBs // + ); + + // + // Extract Available Order Blocks ... + int bullishOBsCont = FilterZones( + // + bullishOBs, + // + X_DIRECTION_BULLISH, + analyseState.period, + NULL, + // + // Start ... + XZONE_STATE_IGNORED, + false, + // + // Activation ... + XZONE_STATE_IGNORED, + false, + // + // Breake ... + XZONE_STATE_FAILED, + false, + // + // Work ... + XZONE_STATE_IGNORED, + false, + // + true, // Apply Sore ... + true // Ignore Inside ... + ); + bool hasBullishOBs = HasChild(bullishOBs); + + // + XCOrderBlock *bearishOBs[]; + Copy( + analyseState.bearishOrderBlocks, + bearishOBs // + ); + + // + // Extract Available Order Blocks ... + int bearishOBsCont = FilterZones( + // + bearishOBs, + // + X_DIRECTION_BEARISH, + analyseState.period, + NULL, + // + // Start ... + XZONE_STATE_IGNORED, + false, + // + // Activation ... + XZONE_STATE_IGNORED, + false, + // + // Breake ... + XZONE_STATE_FAILED, + false, + // + // Work ... + XZONE_STATE_IGNORED, + false, + // + true, // Apply Sore ... + true // Ignore Inside ... + ); + bool hasBearishOBs = HasChild(bearishOBs); + + // + if (isBullish && + hasBearishOBs) + { + // + int count = ArraySize(bearishOBs); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *iObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateOrderBlock( + bearishOBs[i], + iObj // + ); + if (isCreated) + { + mObjects.Add(iObj); + } + + // + double value = bearishOBs[i].Lower(); + bool canSet = value > entry; + if (canSet) + { + // + Add( + value, + conditions.targets // + ); + } + } + } + + // + if (isBearish && + hasBullishOBs) + { + // + int count = ArraySize(bullishOBs); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *iObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateOrderBlock( + bullishOBs[i], + iObj // + ); + if (isCreated) + { + mObjects.Add(iObj); + } + + // + double value = bullishOBs[i].Upper(); + bool canSet = value < entry; + if (canSet) + { + // + Add( + value, + conditions.targets // + ); + } + } + } + + // + Clean(bullishOBs); + Clean(bearishOBs); + + // + // Detect Quarter Targets ... + + // + double quarterTarget = 0; + if (hasPriority) + { + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + quarterTarget = + isBullish + ? workingZone.supplyZone.Lower() + : workingZone.demandZone.Upper(); + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + quarterTarget = + isBullish + ? workingZone.quarter1 + : workingZone.quarter3; + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + quarterTarget = + isBullish + ? workingZone.quarter2 + : workingZone.quarter2; + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + quarterTarget = + isBullish + ? workingZone.quarter3 + : workingZone.quarter1; + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + quarterTarget = + isBullish + ? workingZone.demandZone.Upper() + : workingZone.supplyZone.Lower(); + break; + } + } + + // + if (quarterTarget > 0) + { + // + Add( + quarterTarget, + conditions.targets // + ); + } + + // + // Cleanup ... + + // + cBar.Clean(); + pBar.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionState.Clean(); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseState.Clean(); + analyseConditions.Clean(); + analyseXConditions.Clean(); + + // + return result; + } + + // + // Detect Guards ... + bool DetectGuards( + // + X121SMCGuard &guards[], + const XPosition &positions[], + // + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // + ) + { + // + bool result = false; + + // + Clean(guards); + + // + bool isCycleHelpersValid = + // + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL + // + ; + + // + return false; + + // + result = isCycleHelpersValid; + if (!result) + { + return result; + } + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + string provider = ToString(X_121_SMC_PROVIDER_XWZ); + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + provider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + result = IsValidSize(count); + if (!result) + { + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + return result; + } + + // + // + // + + // + // Get Global and Common Guards ... + + // + ENUM_X_121_SMC_GUARD_ACTIONS ignoreGuards[1] = { + X_121_SMC_GUARD_ACTION_TRAIL_STOP // + }; + result = DetectX121SMCGuards( + provider, + guards, + positions, + decisionCycleHelper, + analyseCycleHelper, + consolidationCycleHelper, + visionCycleHelper, + // + ignoreGuards + // + ); + + // + // + // + + // + // Get Custom Implemented Guards ... + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Detect Required Data for Analyse Market to Guard Positions ... + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + // + result = HasChild(guards); + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + // + zBar.Clean(); + result = HasChild(guards); + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + result = HasChild(guards); + return result; + } + + // + XOHCL ppBar; + result = ppBar.Init( + symbol, + period, + ppIndex // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + result = HasChild(guards); + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + ppBar.Clean(); + result = HasChild(guards); + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + ppBar.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + ppBar.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + ppBar.Clean(); + + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + + // + analyseConditions.Clean(); + + // + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + consolidationConditions.Clean(); + + // + result = HasChild(guards); + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // + // + + // + // Detect Consolidation Zone ... + + // + // Bullish ... + XConsolidationZone bullishConsolidationZone; + bool hasBullishConsolidationZone = decisionCycleHelper + .GetLastDirectionalConsolidationZone( + X_DIRECTION_BULLISH, + bullishConsolidationZone // + ); + + // + // Bearish ... + XConsolidationZone bearishConsolidationZone; + bool hasBearishConsolidationZone = decisionCycleHelper + .GetLastDirectionalConsolidationZone( + X_DIRECTION_BEARISH, + bearishConsolidationZone // + ); + + // + // Detect High Probability Swings ... + bool isSwingLow = + // + cBar.low > pBar.low && + ppBar.low > pBar.low && + // + zBar.low > pBar.low + // + ; + bool isSwingHigh = + // + cBar.high < pBar.high && + ppBar.high < pBar.high && + // + zBar.high < pBar.high + // + ; + bool isStrongSwingLow = + pBar.IsBullish() && + pBar.GetLowShadow() >= pBar.GetBody() * 2; + bool isStrongSwingHigh = + pBar.IsBearish() && + pBar.GetHighShadow() >= pBar.GetBody() * 2; + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Available Guards: + // X_121_SMC_GUARD_ACTION_NONE + // X_121_SMC_GUARD_ACTION_CLOSE + // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // X_121_SMC_GUARD_ACTION_HEDGE + + // + // X_121_SMC_GUARD_ACTION_CLOSE: + // Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // Close All Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // Close All Long Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // Close All Short Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // Partial Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // Trail Stop Specified Position on Specified Conditions ... + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + bool isLong = IsLong(iPosition.type); + bool isInProfit = iPosition.profit > 0; + + // + double sl = iPosition.sl; + double tp = iPosition.tp; + + // + // Trail Stops Using Consolidation Zones ... + bool canTraiLonglUsingCZone = + // + (isLong && + isInProfit && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > iPosition.sl && + bullishConsolidationZone.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingCZone) + { + sl = bullishConsolidationZone.lower; + } + + // + bool canTraiShortlUsingCZone = + // + (!isLong && + isInProfit && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < iPosition.sl && + bearishConsolidationZone.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingCZone) + { + sl = bearishConsolidationZone.upper; + } + + // + bool canTrailUsingCZone = + canTraiLonglUsingCZone || + canTraiShortlUsingCZone; + + // + // Trail Stops Using Swings ... + + // + bool canTrailLongUsingSwings = + // + isLong && + isInProfit && + (isSwingLow || + isStrongSwingLow) && + pBar.low > iPosition.sl && + pBar.low > iPosition.entry + // + ; + if (canTrailLongUsingSwings) + { + sl = pBar.low; + } + + // + bool canTraiShortlUsingSwings = + // + !isLong && + isInProfit && + (isSwingHigh || + isStrongSwingHigh) && + pBar.high < iPosition.sl && + pBar.high < iPosition.entry + // + ; + if (canTraiShortlUsingSwings) + { + sl = pBar.high; + } + + // + bool canTrailUsingSwings = + canTrailLongUsingSwings || + canTraiShortlUsingSwings; + + // + // + // + + // + bool canTrail = + sl != iPosition.sl && + (canTrailUsingCZone || + canTrailUsingSwings); + if (canTrail) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.ticket = iPosition.ticket; + + // + iGuard.sl = sl; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // Trail Target Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_HEDGE: + // Hedge all Positions on Specified Conditions ... + + // + // Cleanup Collections ... + + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + ppBar.Clean(); + + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(visionCycleEvents); + Clean(decisionPoiEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + + // + visionState.Clean(); + analyseState.Clean(); + decisionState.Clean(); + visionConditions.Clean(); + analyseConditions.Clean(); + visionXConditions.Clean(); + decisionConditions.Clean(); + consolidationState.Clean(); + analyseXConditions.Clean(); + decisionXConditions.Clean(); + consolidationConditions.Clean(); + consolidationXConditions.Clean(); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + // + // Add Conditions to Conditions Collection ... + int AddConditionsIfNotExists( + int maxAllowed = 10 // + ) + { + // + int result = 0; + + // + bool isSetuped = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(mConditionsCollection); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXWZSignalConditions tmpItems[]; + Copy( + mConditionsCollection, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(mConditions.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXWZSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = mConditions.dir == iItem.dir && + mConditions.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + mConditionsCollection, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + mConditions, + mConditionsCollection // + ); + + // + // Remove Olds ... + CleanupArray( + mConditionsCollection, + maxAllowed // + ); + + // + result = ArraySize(mConditionsCollection); + + // + return result; + } + + // + bool DetectWorkingZone( + XPOIState <fState // + ) + { + // + bool result = false; + + // + result = IsValid(symbol) && + IsValid(period); + if (!result) + { + return result; + } + + // + result = !workingZone.IsValid(); + if (!result) + { + return result; + } + + // + workingZone.symbol = symbol; + workingZone.period = period; + + // + int idx = -1; + bool has = false; + + // + has = ltfState.HasSupplyZones(); + if (has) + { + // + idx = GetHighest(ltfState.supplyZones); + if (IsValidIndex(idx)) + { + workingZone.supplyZone = ltfState.supplyZones[idx]; + } + } + + // + has = ltfState.HasDemandZones(); + if (has) + { + // + idx = GetLowest(ltfState.demandZones); + if (IsValidIndex(idx)) + { + workingZone.demandZone = ltfState.demandZones[idx]; + } + } + + // + bool hasWorkingZone = workingZone.HasSupplyZone() && + workingZone.HasDemandZone(); + if (hasWorkingZone) + { + // + double upper = workingZone.supplyZone.Lower(); + double lower = workingZone.demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + workingZone.quarter1 = upper - (1 * delta); + workingZone.quarter2 = upper - (2 * delta); + workingZone.quarter3 = upper - (3 * delta); + + // + hasWorkingZone = workingZone.IsValid(); + } + + // + result = hasWorkingZone; + + // + return result; + } + + // + // Draw Functions ... + // + + // + void RemoveDraws() + { + mObjects.Clear(); + } + + // + void DrawBar( + XOHCL &bar, + XCPOIDrawer *drawer, + bool forceClean = true // + ) + { + // + if (forceClean) + { + mBarObjects.Clear(); + } + + // + if (drawer == NULL || + !bar.IsValid()) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + + // + int widthBar = 2; + bool fillShadowsBar = true; + ENUM_LINE_STYLE styleBar = STYLE_SOLID; + color clrBar = + isBullish + ? clrAqua + : clrMagenta; + + // + datetime to = bar.NextAt(); + + // + XCOHCLObject *iObj; + bool isCreated = drawer + .CreateBar( + bar, + iObj, + to // + ); + if (isCreated) + { + // + iObj.BarSpes( + widthBar, + clrBar, + styleBar // + ); + + // + iObj.LowShadowFill(fillShadowsBar); + iObj.HighShadowFill(fillShadowsBar); + + // + mBarObjects.Add(iObj); + } + } + + // + void DrawWorkingZone( + XCPOIDrawer *drawer, + bool drawTrendLine = true, + bool forceClean = false // + ) + { + // + if (drawer == NULL) + { + return; + } + + // + if (forceClean) + { + mWorkingZoneObjects.Clear(); + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + ulong chartID = drawer.ChartIdentification(); + int subWindow = drawer.SubWindowIdentification(); + color bullishColor = drawer.BarBullishColor(); + color bearishColor = drawer.BarBearishColor(); + + // + // Supply Zone ... + has = workingZone.HasSupplyZone(); + if (has) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + workingZone.supplyZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + + // + has = workingZone.HasSupplyZones(); + if (has) + { + // + count = workingZone.CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + workingZone.supplyZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Demand Zone ... + has = workingZone.HasDemandZone(); + if (has) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + workingZone.demandZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + + // + has = workingZone.HasDemandZones(); + if (has) + { + // + count = workingZone.CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + workingZone.demandZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Quarters ... + has = workingZone.IsValid(); + if (has) + { + // + double zoneUpper = workingZone.supplyZone.Upper(); + double upper = workingZone.supplyZone.Lower(); + + // + double lower = workingZone.demandZone.Upper(); + double zoneLower = workingZone.demandZone.Lower(); + + // + string prefix = "X121WZone_" + workingZone.symbol + "_" + ToString(workingZone.period); + + // + // Zone Upper ... + CChartObjectHLine *zoneUpperLine; + zoneUpperLine = new CChartObjectHLine(); + isCreated = zoneUpperLine.Create( + chartID, + prefix + "_ZoneTop", + subWindow, + zoneUpper // + ); + if (isCreated) + { + // + zoneUpperLine.Color(clrRed); + + // + mWorkingZoneObjects.Add(zoneUpperLine); + } + + // + // Zone Lower ... + CChartObjectHLine *zoneLowerLine; + zoneLowerLine = new CChartObjectHLine(); + isCreated = zoneLowerLine.Create( + chartID, + prefix + "_ZoneDown", + subWindow, + zoneLower // + ); + if (isCreated) + { + // + zoneLowerLine.Color(clrRed); + + // + mWorkingZoneObjects.Add(zoneLowerLine); + } + + // + // Upper ... + CChartObjectHLine *upperLine; + upperLine = new CChartObjectHLine(); + isCreated = upperLine.Create( + chartID, + prefix + "_Upper", + subWindow, + upper // + ); + if (isCreated) + { + // + upperLine.Color(clrLime); + + // + mWorkingZoneObjects.Add(upperLine); + } + + // + // Lower ... + CChartObjectHLine *lowerLine; + lowerLine = new CChartObjectHLine(); + isCreated = lowerLine.Create( + chartID, + prefix + "_Lower", + subWindow, + lower // + ); + if (isCreated) + { + // + lowerLine.Color(clrLime); + + // + mWorkingZoneObjects.Add(lowerLine); + } + + // + // Quarters ... + + // + // Quarter 1 ... + CChartObjectHLine *q1Line; + q1Line = new CChartObjectHLine(); + isCreated = q1Line.Create( + chartID, + prefix + "_Q1", + subWindow, + workingZone.quarter1 // + ); + if (isCreated) + { + // + q1Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q1Line); + } + + // + // Quarter 2 ... + CChartObjectHLine *q2Line; + q2Line = new CChartObjectHLine(); + isCreated = q2Line.Create( + chartID, + prefix + "_Q2", + subWindow, + workingZone.quarter2 // + ); + if (isCreated) + { + // + q2Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q2Line); + } + + // + // Quarter 3 ... + CChartObjectHLine *q3Line; + q3Line = new CChartObjectHLine(); + isCreated = q3Line.Create( + chartID, + prefix + "_Q3", + subWindow, + workingZone.quarter3 // + ); + if (isCreated) + { + // + q3Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q3Line); + } + } + + // + // Draw Order Flow ... + ENUM_X_DIRECTION trend; + has = workingZone.HasOrderFlow(trend); + if (has) + { + // + bool isBullish = IsBullish(trend); + + // + count = workingZone.CountOrderFlow(); + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = workingZone.orderFlow[i]; + + // + XCBaseObject *drawnObjects[]; + int drawnObjectsCount = drawer + .DrawOBFVG( + // + iOBFVG, + drawnObjects, + // + true, // Draw Order Block ... + true, // Draw Fair Value Gap ... + false, // Draw Supply Zones ... + false, // Draw Demand Zones ... + false, // Draw Support Zones ... + false // Draw Resistance Zones ... + ); + if (IsValidSize(drawnObjectsCount)) + { + AddDrawnWorkingZoneObjects(drawnObjects); + } + } + + // + // Draw Trend Line ... + if (drawTrendLine) + { + // + XOBFVGPivot pivots[]; + count = workingZone.GetSwings(pivots); + has = count >= 2; + if (has) + { + // + // Get Max / Min ... + double max = 0; + double min = 0; + datetime maxAt = NULL; + datetime minAt = NULL; + for (int i = 0; i < count; i++) + { + // + XOBFVGPivot iPivot = pivots[i]; + + // + if (!iPivot.IsValid()) + { + // + iPivot.Clean(); + continue; + } + + // + // Min ... + bool canSetMin = + min == 0 + ? true + : min > iPivot.value; + if (canSetMin) + { + // + minAt = iPivot.at; + min = iPivot.value; + } + + // + // Max ... + bool canSetMax = + max == 0 + ? true + : max < iPivot.value; + if (canSetMax) + { + // + maxAt = iPivot.at; + max = iPivot.value; + } + + // + iPivot.Clean(); + } + + // + double price1 = + isBullish + ? min + : max; + double price2 = + isBullish + ? max + : min; + datetime time1 = + isBullish + ? minAt + : maxAt; + datetime time2 = + isBullish + ? maxAt + : minAt; + + // + color clrTrend = + isBullish + ? bullishColor + : bearishColor; + + // + string trendName = + ToString(trend) + "_" + "XTRNDL_" + + ToString(period) + "_" + + ToString(price1) + "_" + + ToString(price2) + "_"; + // + ToMD5(ToString(time1)); + + // + CChartObjectTrend *mTrend; + mTrend = new CChartObjectTrend(); + isCreated = mTrend.Create( + chartID, + trendName, + subWindow, + time1, + price1, + time2, + price2 // + ); + + // + if (isCreated) + { + // + mTrend.Width(2); + mTrend.Color(clrTrend); + mTrend.RayRight(true); + + // + mWorkingZoneObjects.Add(mTrend); + } + } + } + + // + // Draw Target Zone ... + has = targetZone.IsValid(); + if (has) + { + // + XCBaseObject *drawnObjects[]; + int drawnObjectsCount = drawer + .DrawOBFVG( + // + targetZone, + drawnObjects, + // + true, // Draw Order Block ... + true, // Draw Fair Value Gap ... + false, // Draw Supply Zones ... + false, // Draw Demand Zones ... + false, // Draw Support Zones ... + false // Draw Resistance Zones ... + ); + if (IsValidSize(drawnObjectsCount)) + { + AddDrawnWorkingZoneObjects(drawnObjects); + } + } + } + + // + } + + // + void DrawConditions( + X121SMCStrategyXWZSignalConditions &conditions, + XCPOIDrawer *drawer, + bool forceClean = false // + ) + { + // + if (drawer == NULL) + { + return; + } + + // + if (forceClean) + { + mObjects.Clear(); + } + + // + bool hasSignalZone = conditions.signalZone.IsValid(); + if (hasSignalZone) + { + // + XCBaseObject *iObjects[]; + int iObjectsCount = drawer.DrawOBFVG( + conditions.signalZone, + iObjects // + ); + AddDrawnObjects(iObjects); + } + } + + // + protected: + // + + // + private: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + CArrayObj mObjects; + CArrayObj mBarObjects; + CArrayObj mWorkingZoneObjects; + + /** + * Initialize ... + */ + void Init() + { + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + chochZone.Clean(); + signalZone.Clean(); + targetZone.Clean(); + mConditions.Clean(); + workingZone.Clean(); + Clean(mConditionsCollection); + + // + mObjects.Clear(); + mBarObjects.Clear(); + mWorkingZoneObjects.Clear(); + } + + /** + * Update To Time of Exists Components ... + * + * @param value: updated time ... + */ + void UpdateTo( + datetime value = NULL // + ) + { + // + value = NormalizeTime(value); + + // + chochZone.UpdateTo(value); + targetZone.UpdateTo(value); + signalZone.UpdateTo(value); + workingZone.UpdateTo(value); + mConditions.UpdateTo(value); + waitingZone.UpdateTo(value); + } + + // + // Helpers ... + + // + bool CalculateRiskReward( + ENUM_X121SMC_XWZ_PRIORITY priority, + double &reward, + double &amountPercent // + ) + { + // + bool result = false; + + // + reward = 0; + amountPercent = 0; + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE; + if (!result) + { + return result; + } + + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + reward = 6; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + reward = 4; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + reward = 3; + amountPercent = 1.5; + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + reward = 2; + amountPercent = 1; + break; + + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + reward = 1; + amountPercent = 0.5; + break; + } + + // + result = + // + reward > 0 && + amountPercent > 0 + // + ; + + // + return result; + } + + // + void AddDrawnObjects(XCBaseObject *&objects[]) + { + // + int count = ArraySize(objects); + bool has = IsValidSize(count); + if (!has) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + mObjects.Add(objects[i]); + } + } + + // + void AddDrawnWorkingZoneObjects(XCBaseObject *&objects[]) + { + // + int count = ArraySize(objects); + bool has = IsValidSize(count); + if (!has) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + mWorkingZoneObjects.Add(objects[i]); + } + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy 2.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy 2.mq5 new file mode 100644 index 0000000..8aa5b9c --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy 2.mq5 @@ -0,0 +1,3189 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +enum ENUM_X121SMC_XWZ_PROVIDERS +{ + X121SMC_XWZ_PROVIDER_NONE, + X121SMC_XWZ_PROVIDER_PV_ZONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH, + X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE, +}; + +// +enum ENUM_X121SMC_XWZ_PRIORITY +{ + X121SMC_XWZ_PRIORITY_NONE, + X121SMC_XWZ_PRIORITY_WEAK, + X121SMC_XWZ_PRIORITY_LOW, + X121SMC_XWZ_PRIORITY_REGULAR, + X121SMC_XWZ_PRIORITY_HIGH, + X121SMC_XWZ_PRIORITY_STRONG_HIGH, +}; + +// +// Definitions ... + +// +struct X121SMCStrategyXWZWorkingZone +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double quarter1; + double quarter2; + double quarter3; + + // + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + + // + XCSupplyZone *supplyZones[]; + XCDemandZone *demandZones[]; + + // + XCSupportZone *supportZones[]; + XCResistanceZone *resistanceZones[]; + + // + XBoxZone insideBoxes[]; + XBoxZone breakedBoxes[]; + XBoxZone waitingBoxes[]; + XBoxZone breakedInsideBoxes[]; + XConsolidationZone consolidationZones[]; + + // + CArrayObj mInsideZoneObjects; + CArrayObj mBreakedZoneObjects; + CArrayObj mWaitingZoneObjects; + CArrayObj mWorkingZoneObjects; + CArrayObj mBreakedInsideZoneObjects; + + // + bool mUseSupDems; + bool mUseOrderBlocks; + bool mUseFairValueGaps; + + // + // Constructor ... + X121SMCStrategyXWZWorkingZone() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + quarter1 = 0; + quarter2 = 0; + quarter3 = 0; + + // + symbol = NULL; + period = NULL; + + // + Clean(supplyZones); + Clean(demandZones); + + // + Clean(insideBoxes); + Clean(breakedBoxes); + Clean(waitingBoxes); + + // + Clean(supportZones); + Clean(resistanceZones); + + // + ZeroMemory(supplyZone); + ZeroMemory(demandZone); + + // + mInsideZoneObjects.Clear(); + mBreakedZoneObjects.Clear(); + mWaitingZoneObjects.Clear(); + mWorkingZoneObjects.Clear(); + mBreakedInsideZoneObjects.Clear(); + + // + mUseSupDems = false; + mUseOrderBlocks = true; + mUseFairValueGaps = true; + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + // + quarter1 > 0 && + quarter2 > 0 && + quarter3 > 0 && + HasSupplyZone() && + HasDemandZone() && + quarter1 > quarter2 && + quarter2 > quarter3 + // + ; + + // + return result; + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, // + XPOIState &ttfState // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + ttfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() && + ttfState.HasChild() + // + ; + if (!result) + { + return result; + } + + // + symbol = _symbol; + period = _period; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + result = has; + if (!result) + { + zBar.Clean(); + return result; + } + double ll5 = zBar.FindLowest(5, MODE_LOW); + double hh5 = zBar.FindHighest(5, MODE_HIGH); + zBar.Clean(); + + // + // Supply Zone ... + has = HasSupplyZone(); + if (!has) + { + // + idx = GetHighest(mtfState.supplyZones); + has = IsValidIndex(idx); + if (has) + { + // + supplyZone = mtfState.supplyZones[idx]; + has = hh5 < supplyZone.Lower(); + if (!has) + { + supplyZone = NULL; + } + } + } + + // + // Demand Zone ... + has = HasDemandZone(); + if (!has) + { + // + idx = GetLowest(mtfState.demandZones); + has = IsValidIndex(idx); + if (has) + { + // + demandZone = mtfState.demandZones[idx]; + has = ll5 > demandZone.Upper(); + if (!has) + { + demandZone = NULL; + } + } + } + + // + // + // + + // // + // // Supply Zones ... + // has = HasSupplyZones(); + // if (!has) + // { + // // + // count = mtfState.FilterSupplyZones( + // supplyZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // // + // // Demand Zones ... + // has = HasDemandZones(); + // if (!has) + // { + // // + // count = mtfState.FilterDemandZones( + // demandZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // + // Support Zones ... + // has = HasSupportZones(); + // if (!has) + // { + // // + // count = mtfState.FilterSupportZones( + // supportZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // + // Resistance Zones ... + // has = HasResistanceZones(); + // if (!has) + // { + // // + // count = mtfState.FilterResistanceZones( + // resistanceZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // + has = ttfState.HasConsolidationZones(); + if (has) + { + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); + } + + // + if (supplyZone != NULL && + demandZone != NULL && + supplyZone.IsValid() && + demandZone.IsValid()) + { + // + double upper = supplyZone.Lower(); + double lower = demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + quarter1 = upper - (1 * delta); + quarter2 = upper - (2 * delta); + quarter3 = upper - (3 * delta); + } + + // + // Waiting Zone Detection ... + // XPOIState iState = mtfState; + + // + // Detect Waiting Zones ... + + // // + // // Using Order Blocks ... + // if (mUseOrderBlocks) + // { + // // + // has = iState.HasOrderBlocks(); + // if (has) + // { + // // + // XCOrderBlock *obs[]; + // count = iState.FilterOrderBlocks( + // obs, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + + // // + // has = IsValidSize(count); + // if (has) + // { + // // + // ToBox( + // obs, + // waitingBoxes // + // ); + // } + + // // + // Clean(obs); + // } + // } + + // // + // // Using Fair Value Gaps ... + // if (mUseFairValueGaps) + // { + // // + // has = iState.HasFairValueGaps(); + // if (has) + // { + // // + // XBoxZone boxes[]; + // XCFVG *fvgs[]; + // count = iState.FilterFairValueGaps( + // fvgs, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + + // // + // has = IsValidSize(count); + // if (has) + // { + // // + // count = ToBox( + // fvgs, + // boxes // + // ); + + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox = boxes[i]; + + // // + // int idx = FindIndex( + // iBox, + // waitingBoxes // + // ); + // has = !IsValidIndex(idx); + // if (has) + // { + // // + // AddRef( + // iBox, + // waitingBoxes // + // ); + // } + + // // + // iBox.Clean(); + // } + // } + + // // + // Clean(fvgs); + // Clean(boxes); + // } + // } + + // + // Cleaning State ... + // iState.Clean(); + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + // + void Update( + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState // + ) + { + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + has = + // + IsValid() && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() + // + ; + if (!has) + { + return; + } + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + zBar.Clean(); + return; + } + + // + XOHCL cBar; + has = zBar.GetPreviousBar(cBar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + + // + return; + } + + // + // Update Exists Zones ... + + // + // Supply Zones ... + has = mtfState.HasSupplyZones(); + if (has) + { + // + XCSupplyZone *zone; + idx = GetYoungest(mtfState.supplyZones); + has = IsValidIndex(idx); + if (has) + { + // + zone = mtfState.supplyZones[idx]; + has = IsSupplyExists(zone); + if (!has) + { + // + Add( + zone, + supplyZones // + ); + } + else + { + ZeroMemory(zone); + } + } + } + + // + // Demand Zones ... + has = mtfState.HasDemandZones(); + if (has) + { + // + XCDemandZone *zone; + idx = GetYoungest(mtfState.demandZones); + has = IsValidIndex(idx); + if (has) + { + // + zone = mtfState.demandZones[idx]; + has = IsDemandExists(zone); + if (!has) + { + // + Add( + zone, + demandZones // + ); + } + else + { + ZeroMemory(zone); + } + } + } + + // + // + // + + // + // Supply Zones ... + has = HasSupplyZones(); + if (has) + { + // + int removeIDXs[]; + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = supplyZones[i]; + ENUM_X_DIRECTION iDir = X_DIRECTION_BEARISH; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + XOHCL passedBar; + bool isBodyIn = false; + bool isBodyOut = false; + + // + // Check Activation ... + bool isActivated = iZone.IsActivated( + iDir, + passedBar, + isBodyIn, + true, + period // + ); + if (isActivated) + { + // + // AddRef( + // iBox, + // insideBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + // Checking Breaked ... + bool isBreaked = iZone.IsBreaked( + iDir, + passedBar, + isBodyOut, + false, + true, + period // + ); + if (isBreaked) + { + // // + // AddRef( + // iBox, + // breakedBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + passedBar.Clean(); + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + supplyZones // + ); + } + + // + Clean(removeIDXs); + } + + // + // Demand Zones ... + has = HasDemandZones(); + if (has) + { + // + int removeIDXs[]; + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = demandZones[i]; + ENUM_X_DIRECTION iDir = X_DIRECTION_BULLISH; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + XOHCL passedBar; + bool isBodyIn = false; + bool isBodyOut = false; + + // + // Check Activation ... + bool isActivated = iZone.IsActivated( + iDir, + passedBar, + isBodyIn, + true, + period // + ); + if (isActivated) + { + // + // AddRef( + // iBox, + // insideBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + // Checking Breaked ... + bool isBreaked = iZone.IsBreaked( + iDir, + passedBar, + isBodyOut, + false, + true, + period // + ); + if (isBreaked) + { + // // + // AddRef( + // iBox, + // breakedBoxes // + // ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + passedBar.Clean(); + continue; + } + + // + passedBar.Clean(); + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + demandZones // + ); + } + + // + Clean(removeIDXs); + } + + // + // Update Boxes ... + + // + // Waiting Boxes ... + has = HasWaitingBoxes(); + if (has) + { + // + int removeIDXs[]; + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = waitingBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isInside = + // + zBar.low < iBox.upper && + zBar.low > iBox.lower + // + ; + if (isInside) + { + // + AddRef( + iBox, + insideBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + + // + bool isBreakedUpper = + // + cBar.low < iBox.upper && + cBar.low > iBox.lower && + zBar.low > iBox.upper + // + ; + + // + bool isBreakedLower = + // + cBar.high > iBox.lower && + cBar.high < iBox.upper && + zBar.high < iBox.lower + // + ; + + // + bool isBreaked = + (isBullish && + isBreakedLower) || + (!isBullish && + isBreakedUpper); + + // + if (isBreaked) + { + // + AddRef( + iBox, + breakedBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + waitingBoxes // + ); + } + + // + Clean(removeIDXs); + } + + // + // Inside Boxes ... + has = HasInsideBoxes(); + if (has) + { + // + int removeIDXs[]; + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = insideBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isBreakedUpper = + // + cBar.low < iBox.upper && + cBar.low > iBox.lower && + zBar.low > iBox.upper + // + ; + + // + bool isBreakedLower = + // + cBar.high > iBox.lower && + cBar.high < iBox.upper && + zBar.high < iBox.lower + // + ; + + // + bool isBreaked = + (isBullish && + isBreakedLower) || + (!isBullish && + isBreakedUpper); + + // + if (isBreaked) + { + // + AddRef( + iBox, + breakedBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + insideBoxes // + ); + } + + // + Clean(removeIDXs); + } + + // + has = HasBreakedBoxes(); + if (has) + { + // + int removeIDXs[]; + count = CountBreakedBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = breakedBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = IsBullish(iDir); + + // + bool isInside = false; + + // + if (isInside) + { + // + AddRef( + iBox, + breakedInsideBoxes // + ); + + // + Add( + i, + removeIDXs // + ); + + // + iBox.Clean(); + break; + } + } + + // + count = ArraySize(removeIDXs); + has = IsValidSize(count); + if (has) + { + // + CleanupArray( + removeIDXs, + breakedBoxes // + ); + } + + // + Clean(removeIDXs); + } + + // + // Update Waiting Boxes ... + + // + XPOIState iState = mtfState; + + // + // Use Order Blocks ... + if (mUseOrderBlocks) + { + // + has = iState.HasOrderBlocks(); + if (has) + { + // + XCOrderBlock *obs[]; + count = iState.FilterOrderBlocks( + obs, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + + // + has = IsValidSize(count); + if (has) + { + // + // Try to Add new OBs into Waiting Zones ... + // if it's not exists ... + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + obs[i] // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Waiting Boxes ... + idx = FindIndex( + iBox, + waitingBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Inside Boxes ... + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Breaked Boxes ... + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + AddRef( + iBox, + waitingBoxes // + ); + } + } + + // + Clean(obs); + } + } + + // + // Use Fair Value Gaps ... + if (mUseFairValueGaps) + { + // + has = iState.HasFairValueGaps(); + if (has) + { + // + XCFVG *fvgs[]; + count = iState.FilterFairValueGaps( + fvgs, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + + // + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + fvgs[i] // + ); + if (!hasBox) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Waiting Boxes ... + idx = FindIndex( + iBox, + waitingBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Inside Boxes ... + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Check Index in Breaked Boxes ... + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + AddRef( + iBox, + waitingBoxes // + ); + + // + iBox.Clean(); + } + } + + // + Clean(fvgs); + } + } + + // + iState.Clean(); + + // + // Cleanup Resource ... + + // + zBar.Clean(); + cBar.Clean(); + } + + // + bool IsDestroyed( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL cBar; + result = bar.GetPreviousBar(cBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + bool isSupplyZoneBreaked = + // + bar.low > supplyZone.Upper() && + cBar.low > supplyZone.Upper() + // + ; + + // + bool isDemandZoneBreaked = + // + bar.high < demandZone.Lower() && + cBar.high < demandZone.Lower() + // + ; + + // + bar.Clean(); + cBar.Clean(); + + // + result = isSupplyZoneBreaked || + isDemandZoneBreaked; + + // + return result; + } + + // + bool DetectPriority( + ENUM_X121SMC_XWZ_PRIORITY &priority, + ENUM_X_DIRECTION forDir, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + priority = X121SMC_XWZ_PRIORITY_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + if (bar.high < supplyZone.Upper() && + bar.low > supplyZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_NONE + : X121SMC_XWZ_PRIORITY_STRONG_HIGH; + } + else if (bar.high < supplyZone.Lower() && + bar.low > quarter1) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_WEAK + : X121SMC_XWZ_PRIORITY_HIGH; + } + else if (bar.high < quarter1 && + bar.low > quarter2) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_LOW + : X121SMC_XWZ_PRIORITY_REGULAR; + } + else if (bar.high < quarter2 && + bar.low > quarter3) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_REGULAR + : X121SMC_XWZ_PRIORITY_LOW; + } + else if (bar.high < quarter3 && + bar.low > demandZone.Upper()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_HIGH + : X121SMC_XWZ_PRIORITY_WEAK; + } + else if (bar.high < demandZone.Upper() && + bar.low > demandZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_STRONG_HIGH + : X121SMC_XWZ_PRIORITY_NONE; + } + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE && + priority != X121SMC_XWZ_PRIORITY_WEAK; + + // + bar.Clean(); + + // + return result; + } + + // + bool DetectSenarioASignalBox( + XBoxZone &signalBox, + ENUM_X_DIRECTION &signalDir, + X121Conditions &decisionXConditions, + X121Conditions &analyseXConditions, + XC121SMCCycleHelper *decisionCycleHelper, + XCPOIDrawer *drawer = NULL, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + signalBox.Clean(); + signalDir = X_DIRECTION_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = decisionCycleHelper != NULL; + if (!result) + { + return result; + } + + // + // Decision ... + double decisionBullishScore = 0; + double decisionBearishScore = 0; + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + double analyseBullishScore = 0; + double analyseBearishScore = 0; + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // Score Conditions ... + double scoreMultiplier = 3; + bool isBullishScorePassed = + // + analyseBullishScore > (analyseBearishScore * scoreMultiplier) && + decisionBullishScore > (decisionBearishScore * scoreMultiplier) + // + ; + bool isBearishScorePassed = + // + analyseBearishScore > (analyseBullishScore * scoreMultiplier) && + decisionBearishScore > (decisionBullishScore * scoreMultiplier) + // + ; + + // + // Checking Other Conditions + + // + bool isCommonBullish = + // + decisionXConditions.isSarBullish && + decisionXConditions.isStrBullish && + decisionXConditions.isCheBullish && + decisionXConditions.isSMHKBullish && + decisionXConditions.isRawHKBullish && + decisionXConditions.isRawHKClosedOverSMHK + // + ; + + // + bool isCommonBearish = + // + decisionXConditions.isSarBearish && + decisionXConditions.isStrBearish && + decisionXConditions.isCheBearish && + decisionXConditions.isSMHKBearish && + decisionXConditions.isRawHKBearish && + decisionXConditions.isRawHKClosedUnderSMHK + // + ; + + // + // X3Ma ... + + // + // X3Ma Bullish ... + bool isX3MaBullish = + // + decisionXConditions.isX3MaBullishState && + decisionXConditions.isX3MaSwitchedToBullishOrdered && + decisionXConditions.x3maMidBuffer[1] > decisionXConditions.x3maSlowBuffer[1] + // + ; + + // + // X3Ma Bearish ... + bool isX3MaBearish = + // + decisionXConditions.isX3MaBearishState && + decisionXConditions.isX3MaSwitchedToBearishOrdered && + decisionXConditions.x3maMidBuffer[1] < decisionXConditions.x3maSlowBuffer[1] + // + ; + + // + bool isX3MaHasCondition = + (isX3MaBullish && + isCommonBullish && + isBullishScorePassed) || + (isX3MaBearish && + isCommonBearish && + isBearishScorePassed); + + // + // VWap ... + + // + // VWap Bullish ... + bool isVWapBullish = + // + decisionXConditions.isVWapBullishState && + decisionXConditions.isVWapSwitchedToBullishOrdered && + decisionXConditions.vwapMidBuffer[1] > decisionXConditions.vwapSlowBuffer[1] + // + ; + + // + // VWap Bearish ... + bool isVWapBearish = + // + decisionXConditions.isVWapBearishState && + decisionXConditions.isVWapSwitchedToBearishOrdered && + decisionXConditions.vwapMidBuffer[1] < decisionXConditions.vwapSlowBuffer[1] + // + ; + + // + bool isVWapHasCondition = + (isVWapBullish && + isBullishScorePassed) || + (isVWapBearish && + isBearishScorePassed); + + // + // Senario .... + // - a vale Under X3MA Slow when X3MA Bullish Ordered ... + + // + bool isX3MASenarioBBullish = + // + decisionXConditions.isX3MaBullishOrdered && + decisionXConditions.valesBuffer[1] < decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.valesBuffer[2] >= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBullish) + { + } + + // + bool isX3MASenarioBBearish = + // + decisionXConditions.isX3MaBearishOrdered && + decisionXConditions.peaksBuffer[1] > decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.peaksBuffer[2] <= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBearish) + { + } + + // + // Checking Other Conditions XWZ Reject on EMA 20 ... + + // + // Check Has Conditions ... + bool hasXConditions = + (isX3MaHasCondition || + isVWapHasCondition); + + // + result = hasXConditions; + if (!result) + { + return result; + } + + // + if (isX3MaHasCondition) + { + // + signalDir = + isX3MaBullish + ? X_DIRECTION_BULLISH + : isX3MaBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + if (isVWapHasCondition) + { + // + signalDir = + isVWapBullish + ? X_DIRECTION_BULLISH + : isVWapBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Creating SignalBox ... + + // + // Detect Box based on PV ... + bool hasSignalBox = decisionCycleHelper.GeneratePVBox( + signalBox, + barIndex // + ); + + // + result = + hasSignalBox && + signalDir == signalBox.dir; + + // + if (result) + { + // + XCBoxObject *iObj; + bool isCreated = drawer.DrawBox( + signalBox, + iObj // + ); + if (isCreated) + { + // + iObj.BoxWidth(1); + iObj.BoxColor(clrYellow); + iObj.BoxStyle(STYLE_SOLID); + } + + // + Print("Senario A ..."); + } + + // + return result; + } + + // + bool DetetctSenarioBSignalBox( + XBoxZone &signalBox, + ENUM_X_DIRECTION &signalDir, + X121Conditions &decisionXConditions, + X121Conditions &analyseXConditions, + XC121SMCCycleHelper *decisionCycleHelper, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + signalBox.Clean(); + signalDir = X_DIRECTION_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = decisionCycleHelper != NULL; + if (!result) + { + return result; + } + + // + // Decision ... + double decisionBullishScore = 0; + double decisionBearishScore = 0; + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + double analyseBullishScore = 0; + double analyseBearishScore = 0; + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // Score Conditions ... + double scoreMultiplier = 3; + bool isBullishScorePassed = + // + analyseBullishScore > (analyseBearishScore * scoreMultiplier) && + decisionBullishScore > (decisionBearishScore * scoreMultiplier) + // + ; + bool isBearishScorePassed = + // + analyseBearishScore > (analyseBullishScore * scoreMultiplier) && + decisionBearishScore > (decisionBullishScore * scoreMultiplier) + // + ; + + // + // Senario .... + // - a vale Under X3MA Slow when X3MA Bullish Ordered ... + + // + bool isX3MASenarioBBullish = + // + decisionXConditions.isX3MaBullishOrdered && + decisionXConditions.valesBuffer[1] < decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.valesBuffer[2] >= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBullish) + { + } + + // + bool isX3MASenarioBBearish = + // + decisionXConditions.isX3MaBearishOrdered && + decisionXConditions.peaksBuffer[1] > decisionXConditions.x3maSlowBuffer[1] && + decisionXConditions.peaksBuffer[2] <= decisionXConditions.x3maSlowBuffer[2] + // + ; + if (isX3MASenarioBBearish) + { + } + + // + return result; + } + + // + bool DetectOveralDirection( + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = IsValid() && + HasSupplyZone() && + HasDemandZone(); + if (!result) + { + return result; + } + + // + XBoxZone demBox; + XBoxZone supBox; + result = ToBox( + demBox, + demandZone // + ); + if (!result) + { + // + supBox.Clean(); + demBox.Clean(); + + // + return result; + } + result = ToBox( + supBox, + supplyZone // + ); + if (!result) + { + // + supBox.Clean(); + demBox.Clean(); + + // + return result; + } + + // + XOHCL supPriceOutBar; + XOHCL demPriceOutBar; + result = DetectBoxNearestPriceOut( + supBox, + supPriceOutBar, + period // + ); + if (!result) + { + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + result = DetectBoxNearestPriceOut( + demBox, + demPriceOutBar, + period // + ); + if (!result) + { + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + + // + // Specified Direction ... + dir = + (supPriceOutBar.IsValid() && + demPriceOutBar.IsValid()) + ? supPriceOutBar.time > demPriceOutBar.time + ? X_DIRECTION_BEARISH + : demPriceOutBar.time > supPriceOutBar.time + ? X_DIRECTION_BULLISH + : X_DIRECTION_NONE + : X_DIRECTION_NONE; + + // + result = HasDirection(dir); + + // + // Clean Up Resources ... + + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + + // + bool HasInsideBox( + XBoxZone &box // + ) + { + // + bool result = false; + + // + int index = -1; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int count = 0; + bool has = false; + + // + has = HasWaitingBoxes(); + if (has) + { + // + result = HasInsideBox( + index, + box, + waitingBoxes // + ); + } + + // + // Supply Zones ... + if (!result) + { + // + has = HasSupplyZones(); + if (has) + { + // + XBoxZone tmpBoxes[]; + count = ToBox( + supplyZones, + tmpBoxes // + ); + + // + has = IsValidSize(count); + if (has) + { + // + result = HasInsideBox( + index, + box, + tmpBoxes // + ); + } + + // + Clean(tmpBoxes); + } + } + + // + // Demand Zones ... + if (!result) + { + // + has = HasDemandZones(); + if (has) + { + // + XBoxZone tmpBoxes[]; + count = ToBox( + demandZones, + tmpBoxes // + ); + + // + has = IsValidSize(count); + if (has) + { + // + result = HasInsideBox( + index, + box, + tmpBoxes // + ); + } + + // + Clean(tmpBoxes); + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool IsExists(XBoxZone &box) + { + // + bool result = false; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + bool has = false; + + // + // Checking Index Waiting Box ... + has = HasWaitingBoxes(); + if (has) + { + // + idx = FindIndex( + box, + waitingBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index Inside Boxes ... + has = HasInsideBoxes(); + if (has) + { + // + idx = FindIndex( + box, + insideBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index Breaked Boxes ... + has = HasBreakedBoxes(); + if (has) + { + // + idx = FindIndex( + box, + breakedBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + // Checking Index BreakedInside Boxes ... + has = HasBreakedInsideBoxes(); + if (has) + { + // + idx = FindIndex( + box, + breakedInsideBoxes // + ); + result = !IsValidIndex(idx); + if (!result) + { + return result; + } + } + + // + return result; + } + + // + bool IsSupplyExists(XCSupplyZone *zone) + { + // + bool result = false; + + // + result = zone != NULL && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Converts Zone to Box ... + XBoxZone box; + result = ToBox( + box, + zone // + ); + if (!result) + { + // + box.Clean(); + return result; + } + + // + // Checking Index in SupplyZones ... + int idx = FindIndex( + zone, + supplyZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + box.Clean(); + return result; + } + + // + result = IsExists(box); + + // + box.Clean(); + + // + return result; + } + + // + bool IsDemandExists(XCDemandZone *zone) + { + // + bool result = false; + + // + result = zone != NULL && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Converts Zone to Box ... + XBoxZone box; + result = ToBox( + box, + zone // + ); + if (!result) + { + // + box.Clean(); + return result; + } + + // + // Checking Index in SupplyZones ... + int idx = FindIndex( + zone, + demandZones // + ); + result = !IsValidIndex(idx); + if (!result) + { + // + box.Clean(); + return result; + } + + // + result = IsExists(box); + + // + box.Clean(); + + // + return result; + } + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasSupplyZone(); + if (has) + { + supplyZone.To(value); + } + + // + has = HasDemandZone(); + if (has) + { + demandZone.To(value); + } + + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } + } + + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } + } + + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + supportZones[i].To(value); + } + } + + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + resistanceZones[i].To(value); + } + } + + // + // + // + + // + has = HasWaitingBoxes(); + if (has) + { + // + count = ArraySize(waitingBoxes); + for (int i = 0; i < count; i++) + { + waitingBoxes[i].to = value; + } + } + + // + has = HasInsideBoxes(); + if (has) + { + // + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + insideBoxes[i].to = value; + } + } + + // + has = HasBreakedBoxes(); + if (has) + { + } + + // + has = HasBreakedInsideBoxes(); + if (has) + { + // + count = CountBreakedInsideBoxes(); + for (int i = 0; i < count; i++) + { + breakedInsideBoxes[i].to = value; + } + } + + // + } + + // + void Draw( + XCPOIDrawer *drawer, + bool drawWaitingBoxes = true, + bool drawInsideBoxes = false, + bool drawBreakedBoxes = false, + bool drawBreakedInsideBoxes = false, + bool drawSupplyZone = false, + bool drawDemandZone = false, + bool drawSupplyZones = false, + bool drawDemandZones = false, + bool drawSupportZones = false, + bool drawResistanceZones = false // + ) + { + // + if (drawer == NULL) + { + return; + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + ulong chartID = drawer.ChartIdentification(); + int subWindow = drawer.SubWindowIdentification(); + color bullishColor = drawer.BarBullishColor(); + color bearishColor = drawer.BarBearishColor(); + + // + // Supply Zone ... + if (drawSupplyZone) + { + // + has = HasSupplyZone(); + if (has) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Demand Zone ... + if (drawDemandZone) + { + // + has = HasDemandZone(); + if (has) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // + // + + // + // Supply Zones ... + if (drawSupplyZones) + { + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Demand Zones ... + if (drawDemandZones) + { + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Support Zones ... + if (drawSupportZones) + { + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = drawer.CreateSupportZone( + supportZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Resistance Zones ... + if (drawResistanceZones) + { + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = drawer.CreateResistanceZone( + resistanceZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // + // + + // + // Waiting Boxes ... + if (drawWaitingBoxes) + { + // + has = HasWaitingBoxes(); + if (has) + { + // + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = waitingBoxes[i]; + + // + XCBoxObject *iObj; + bool isCreated = drawer.DrawBox( + iBox, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + + // + iBox.Clean(); + } + } + } + + // + // Inside Boxes ... + if (drawInsideBoxes) + { + // + has = HasInsideBoxes(); + if (has) + { + } + } + + // + // Breaked Boxes ... + if (drawBreakedBoxes) + { + // + has = HasBreakedBoxes(); + if (has) + { + // + } + } + + // + // Breaked Inside Boxes ... + if (drawBreakedInsideBoxes) + { + // + has = HasBreakedInsideBoxes(); + if (has) + { + // + count = CountBreakedInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = breakedInsideBoxes[i]; + XCBoxObject *iObj; + has = drawer.DrawBox( + iBox, + iObj // + ); + if (has) + { + // + iObj.BoxWidth(1); + mBreakedInsideZoneObjects.Add(iObj); + } + } + } + } + + // + // + // + + // + // Quarters ... + has = IsValid(); + if (has) + { + // + double zoneUpper = supplyZone.Upper(); + double upper = supplyZone.Lower(); + + // + double lower = demandZone.Upper(); + double zoneLower = demandZone.Lower(); + + // + string prefix = "X121WZone_" + symbol + "_" + ToString(period); + + // + // Zone Upper ... + CChartObjectHLine *zoneUpperLine; + zoneUpperLine = new CChartObjectHLine(); + isCreated = zoneUpperLine.Create( + chartID, + prefix + "_ZoneTop", + subWindow, + zoneUpper // + ); + if (isCreated) + { + // + zoneUpperLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneUpperLine); + } + + // + // Zone Lower ... + CChartObjectHLine *zoneLowerLine; + zoneLowerLine = new CChartObjectHLine(); + isCreated = zoneLowerLine.Create( + chartID, + prefix + "_ZoneDown", + subWindow, + zoneLower // + ); + if (isCreated) + { + // + zoneLowerLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneLowerLine); + } + + // + // Upper ... + CChartObjectHLine *upperLine; + upperLine = new CChartObjectHLine(); + isCreated = upperLine.Create( + chartID, + prefix + "_Upper", + subWindow, + upper // + ); + if (isCreated) + { + // + upperLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(upperLine); + } + + // + // Lower ... + CChartObjectHLine *lowerLine; + lowerLine = new CChartObjectHLine(); + isCreated = lowerLine.Create( + chartID, + prefix + "_Lower", + subWindow, + lower // + ); + if (isCreated) + { + // + lowerLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(lowerLine); + } + + // + // Quarters ... + + // + // Quarter 1 ... + CChartObjectHLine *q1Line; + q1Line = new CChartObjectHLine(); + isCreated = q1Line.Create( + chartID, + prefix + "_Q1", + subWindow, + quarter1 // + ); + if (isCreated) + { + // + q1Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q1Line); + } + + // + // Quarter 2 ... + CChartObjectHLine *q2Line; + q2Line = new CChartObjectHLine(); + isCreated = q2Line.Create( + chartID, + prefix + "_Q2", + subWindow, + quarter2 // + ); + if (isCreated) + { + // + q2Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q2Line); + } + + // + // Quarter 3 ... + CChartObjectHLine *q3Line; + q3Line = new CChartObjectHLine(); + isCreated = q3Line.Create( + chartID, + prefix + "_Q3", + subWindow, + quarter3 // + ); + if (isCreated) + { + // + q3Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q3Line); + } + } + } + + // + // + // + + // + bool HasSupplyZone() + { + return supplyZone != NULL && + supplyZone.IsValid(); + } + + // + bool HasDemandZone() + { + return demandZone != NULL && + demandZone.IsValid(); + } + + // + bool HasSupplyZones() + { + return HasChild(supplyZones); + } + + // + int CountSupplyZones() + { + return ArraySize(supplyZones); + } + + // + bool HasDemandZones() + { + return HasChild(demandZones); + } + + // + int CountDemandZones() + { + return ArraySize(demandZones); + } + + // + bool HasSupportZones() + { + return HasChild(supportZones); + } + + // + int CountSupportZones() + { + return ArraySize(supportZones); + } + + // + bool HasResistanceZones() + { + return HasChild(resistanceZones); + } + + // + int CountResistanceZones() + { + return ArraySize(resistanceZones); + } + + // + bool HasConsolidationZones() + { + return HasChild(consolidationZones); + } + + // + int CountConsolidationZones() + { + return ArraySize(consolidationZones); + } + + // + bool HasWaitingBoxes() + { + return HasChild(waitingBoxes); + } + + // + int CountWaitingBoxes() + { + return ArraySize(waitingBoxes); + } + + // + bool HasInsideBoxes() + { + return HasChild(insideBoxes); + } + + // + int CountInsideBoxes() + { + return ArraySize(insideBoxes); + } + + // + bool HasBreakedBoxes() + { + return HasChild(breakedBoxes); + } + + // + int CountBreakedBoxes() + { + return ArraySize(breakedBoxes); + } + + // + bool HasBreakedInsideBoxes() + { + return HasChild(breakedInsideBoxes); + } + + // + int CountBreakedInsideBoxes() + { + return ArraySize(breakedInsideBoxes); + } + + // +}; + +// +struct X121SMCStrategyXWZSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double reward; + double amountPercent; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + double sls[]; + double targets[]; + + // + XBoxZone signalBox; + + // + ENUM_X121SMC_XWZ_PRIORITY priority; + ENUM_X121SMC_XWZ_PROVIDERS provider; + + // + // Constructor ... + X121SMCStrategyXWZSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + + // + ZeroMemory(this); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + reward = 0; + amountPercent = 0; + + // + Clean(sls); + Clean(targets); + signalBox.Clean(); + + // + provider = X121SMC_XWZ_PROVIDER_NONE; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + } + + // +}; + +// +// Extension Functions ... + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy.mq5 new file mode 100644 index 0000000..fd0c9ab --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib copy.mq5 @@ -0,0 +1,4871 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +enum ENUM_X121SMC_XWZ_PROVIDERS +{ + X121SMC_XWZ_PROVIDER_NONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH, + X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE, +}; + +// +enum ENUM_X121SMC_XWZ_PRIORITY +{ + X121SMC_XWZ_PRIORITY_NONE, + X121SMC_XWZ_PRIORITY_WEAK, + X121SMC_XWZ_PRIORITY_LOW, + X121SMC_XWZ_PRIORITY_REGULAR, + X121SMC_XWZ_PRIORITY_HIGH, + X121SMC_XWZ_PRIORITY_STRONG_HIGH, +}; + +// +struct X121SMCStrategyXWZWorkingZone +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double quarter1; + double quarter2; + double quarter3; + + // + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + + // + XCSupplyZone *supplyZones[]; + XCDemandZone *demandZones[]; + + // + XCSupportZone *supportZones[]; + XCResistanceZone *resistanceZones[]; + + // + XOBFVG insideZones[]; + XOBFVG breakedZones[]; + XOBFVG waitingZones[]; + + // + XBoxZone insideBoxes[]; + XBoxZone breakedBoxes[]; + XConsolidationZone consolidationZones[]; + + // + CArrayObj mInsideZoneObjects; + CArrayObj mBreakedZoneObjects; + CArrayObj mWaitingZoneObjects; + CArrayObj mWorkingZoneObjects; + + // + // Constructor ... + X121SMCStrategyXWZWorkingZone() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + quarter1 = 0; + quarter2 = 0; + quarter3 = 0; + + // + symbol = NULL; + period = NULL; + + // + Clean(supplyZones); + Clean(demandZones); + + // + Clean(insideZones); + Clean(waitingZones); + Clean(breakedZones); + + // + Clean(insideBoxes); + Clean(breakedBoxes); + + // + Clean(supportZones); + Clean(resistanceZones); + + // + ZeroMemory(supplyZone); + ZeroMemory(demandZone); + + // + mInsideZoneObjects.Clear(); + mBreakedZoneObjects.Clear(); + mWaitingZoneObjects.Clear(); + mWorkingZoneObjects.Clear(); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + // + quarter1 > 0 && + quarter2 > 0 && + quarter3 > 0 && + HasSupplyZone() && + HasDemandZone() && + quarter1 > quarter2 && + quarter2 > quarter3 + // + ; + + // + return result; + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, // + XPOIState &ttfState // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + ttfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() && + ttfState.HasChild() + // + ; + if (!result) + { + return result; + } + + // + symbol = _symbol; + period = _period; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + result = has; + if (!result) + { + zBar.Clean(); + return result; + } + double ll5 = zBar.FindLowest(5, MODE_LOW); + double hh5 = zBar.FindHighest(5, MODE_HIGH); + zBar.Clean(); + + // + // Supply Zone ... + has = HasSupplyZone(); + if (!has) + { + // + idx = GetHighest(htfState.supplyZones); + has = IsValidIndex(idx); + if (has) + { + // + supplyZone = htfState.supplyZones[idx]; + has = hh5 < supplyZone.Lower(); + if (!has) + { + supplyZone = NULL; + } + } + } + + // + // Demand Zone ... + has = HasDemandZone(); + if (!has) + { + // + idx = GetLowest(htfState.demandZones); + has = IsValidIndex(idx); + if (has) + { + // + demandZone = htfState.demandZones[idx]; + has = ll5 > demandZone.Upper(); + if (!has) + { + demandZone = NULL; + } + } + } + + // + // Supply Zones ... + has = HasSupplyZones(); + if (!has) + { + // + count = mtfState.FilterSupplyZones( + supplyZones, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + } + + // + // Demand Zones ... + has = HasDemandZones(); + if (!has) + { + // + count = mtfState.FilterDemandZones( + demandZones, + period, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + } + + // // + // // Support Zones ... + // has = HasSupportZones(); + // if (!has) + // { + // // + // count = stfState.FilterSupportZones( + // supportZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // // + // // Resistance Zones ... + // has = HasResistanceZones(); + // if (!has) + // { + // // + // count = stfState.FilterResistanceZones( + // resistanceZones, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // } + + // + has = ttfState.HasConsolidationZones(); + if (has) + { + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); + } + + // + if (supplyZone != NULL && + demandZone != NULL && + supplyZone.IsValid() && + demandZone.IsValid()) + { + // + double upper = supplyZone.Lower(); + double lower = demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + quarter1 = upper - (1 * delta); + quarter2 = upper - (2 * delta); + quarter3 = upper - (3 * delta); + } + + // + // Detect OBFVG(s) ... + ExtractOBFVGs( + waitingZones, + mtfState, + stfState + // , + // X_OBFVG_FVG_FILTER_ABOVE_BELOW, + // X_OBFVG_FVG_SELECT_HIGHEST_LOWEST // + ); + + // // + // // Detect Waiting Zones based on STF and TTF ... + // XOBFVG tmpWaitingZones[]; + // count = ExtractOBFVGs( + // tmpWaitingZones, + // stfState, + // stfState // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XOBFVG iOBFVG = tmpWaitingZones[i]; + + // // + // idx = FindIndex( + // iOBFVG, + // waitingZones // + // ); + // has = IsValidIndex(idx); + // if (has) + // { + // // + // iOBFVG.Clean(); + // continue; + // } + + // // + // AddRef( + // iOBFVG, + // waitingZones // + // ); + + // // + // iOBFVG.Clean(); + // } + // } + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + // + void Update( + int barIndex, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState, + XPOIState &ttfState // + ) + { + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + has = + // + IsValid() && + // + htfState.IsValid() && + mtfState.IsValid() && + stfState.IsValid() && + // + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() + // + ; + if (!has) + { + return; + } + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + zBar.Clean(); + return; + } + + // + XOHCL cBar; + has = zBar.GetPreviousBar(cBar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + + // + return; + } + + // + // Adding New OBFVG to Waiting Zones if not Exists ... + XOBFVG tmpWaitingZones[]; + count = ExtractOBFVGs( + tmpWaitingZones, + mtfState, + stfState + // , + // X_OBFVG_FVG_FILTER_ABOVE_BELOW, + // X_OBFVG_FVG_SELECT_HIGHEST_LOWEST // + ); + has = IsValidSize(count); + if (has) + { + // + AddIfNotExists( + tmpWaitingZones, + waitingZones // + ); + } + + // + // Detect Waiting Zones based on STF and TTF ... + // Clean(tmpWaitingZones); + // count = ExtractOBFVGs( + // tmpWaitingZones, + // stfState, + // ttfState // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // AddIfNotExists( + // tmpWaitingZones, + // waitingZones // + // ); + // } + + // + // Detect Waiting Zones based on TTF and TTF ... + // Clean(tmpWaitingZones); + // count = ExtractOBFVGs( + // tmpWaitingZones, + // stfState, + // stfState // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // AddIfNotExists( + // tmpWaitingZones, + // waitingZones // + // ); + // } + + // + // Since Usig States for Extracting Supply/Demand or + // Support/Resistance Zones and State's has Max Alllowed Restrication ... + // we have to Manage new Zones and also Hold's Breaked Zones ... + + // + // MTF STF ... + + // + // Supply Zones ... + XCSupplyZone *tmpSupplies[]; + count = mtfState.FilterSupplyZones( + tmpSupplies, + NULL, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + tmpSupplies[i] // + ); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Find Index ... + + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + tmpSupplies[i], + supplyZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Checking Price Validation ... + has = cBar.high < tmpSupplies[i].Lower(); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + Add( + tmpSupplies[i], + supplyZones // + ); + + // + iBox.Clean(); + } + } + Clean(tmpSupplies); + + // + // Demand Zones ... + XCDemandZone *tmpDemands[]; + count = mtfState.FilterDemandZones( + tmpDemands, + NULL, + XZONE_STATE_PASSED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_FAILED, + false, + XZONE_STATE_IGNORED, + false // + ); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + tmpDemands[i] // + ); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Find Index ... + + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + idx = FindIndex( + tmpDemands[i], + demandZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + // Checking Price Validation ... + has = cBar.low > tmpDemands[i].Upper(); + if (!has) + { + // + iBox.Clean(); + continue; + } + + // + Add( + tmpDemands[i], + demandZones // + ); + + // + iBox.Clean(); + } + } + Clean(tmpDemands); + + // // + // // Support Zones ... + // XCSupportZone *tmpSupports[]; + // count = stfState.FilterSupportZones( + // tmpSupports, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpSupports[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpSupports[i], + // supportZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.low > tmpSupports[i].Upper(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpSupports[i], + // supportZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpSupports); + + // // + // // Resistance Zones .. + // XCResistanceZone *tmpResistances[]; + // count = stfState.FilterResistanceZones( + // tmpResistances, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpResistances[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpResistances[i], + // resistanceZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.high < tmpResistances[i].Lower(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpResistances[i], + // resistanceZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpResistances); + + // + // STF TTF ... + + // // + // // Supply Zones ... + // count = stfState.FilterSupplyZones( + // tmpSupplies, + // NULL, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpSupplies[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpSupplies[i], + // supplyZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.high < tmpSupplies[i].Lower(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpSupplies[i], + // supplyZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpSupplies); + + // // + // // Demand Zones ... + // count = stfState.FilterDemandZones( + // tmpDemands, + // NULL, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpDemands[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpDemands[i], + // demandZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.low > tmpDemands[i].Upper(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpDemands[i], + // demandZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpDemands); + + // // + // // Support Zones ... + // count = ttfState.FilterSupportZones( + // tmpSupports, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpSupports[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpSupports[i], + // supportZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.low > tmpSupports[i].Upper(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpSupports[i], + // supportZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpSupports); + + // // + // // Resistance Zones .. + // count = ttfState.FilterResistanceZones( + // tmpResistances, + // period, + // XZONE_STATE_PASSED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_FAILED, + // false, + // XZONE_STATE_IGNORED, + // false // + // ); + // has = IsValidSize(count); + // if (has) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XBoxZone iBox; + // has = ToBox( + // iBox, + // tmpResistances[i] // + // ); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Find Index ... + + // // + // idx = FindIndex( + // iBox, + // insideBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // iBox, + // breakedBoxes // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // idx = FindIndex( + // tmpResistances[i], + // resistanceZones // + // ); + // has = !IsValidIndex(idx); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // // Checking Price Validation ... + // has = cBar.high < tmpResistances[i].Lower(); + // if (!has) + // { + // // + // iBox.Clean(); + // continue; + // } + + // // + // Add( + // tmpResistances[i], + // resistanceZones // + // ); + + // // + // iBox.Clean(); + // } + // } + // Clean(tmpResistances); + + // + // + // + + // + // Consolidation Zones ... + has = ttfState.HasConsolidationZones(); + if (has) + { + // + Copy( + ttfState.consolidationZones, + consolidationZones // + ); + CleanupArray( + consolidationZones, + 50 // + ); + } + + // + // + // + + // + // Detect Price Inside Zones ... + has = HasWaitingZones(); + if (has) + { + // + int mustRemove[]; + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = waitingZones[i]; + + // + bool isInside = + // + zBar.high < iOBFVG.ob.Upper() && + zBar.low > iOBFVG.ob.Lower() && + // + cBar.high < iOBFVG.ob.Upper() && + cBar.low > iOBFVG.ob.Lower() + // + ; + if (isInside) + { + // + idx = FindIndex( + iOBFVG, + insideZones // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iOBFVG, + insideZones // + ); + } + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + waitingZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Here we Looking for Price Inside Supply or Demand Zones ... + + // + // Supply Zones ... + has = HasSupplyZones(); + if (has) + { + // + int mustRemove[]; + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = supplyZones[i]; + + // + bool isInside = + // + zBar.high < iZone.Upper() && + zBar.low > iZone.Lower() && + // + cBar.high < iZone.Upper() && + cBar.low > iZone.Lower() + // + ; + if (isInside) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + iZone // + ); + if (has) + { + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iBox, + insideBoxes // + ); + } + } + + // + iBox.Clean(); + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + supplyZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Demand Zones ... + has = HasDemandZones(); + if (has) + { + // + int mustRemove[]; + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = demandZones[i]; + + // + bool isInside = + // + zBar.high < iZone.Upper() && + zBar.low > iZone.Lower() && + // + cBar.high < iZone.Upper() && + cBar.low > iZone.Lower() + // + ; + if (isInside) + { + // + XBoxZone iBox; + has = ToBox( + iBox, + iZone // + ); + if (has) + { + // + idx = FindIndex( + iBox, + insideBoxes // + ); + has = IsValidSize(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iBox, + insideBoxes // + ); + } + } + + // + iBox.Clean(); + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + demandZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Here we Detect Breaked Zone/Box (s) ... + + // + // Detect Breaked Zones ... + has = HasInsideZones(); + if (has) + { + // + int mustRemove[]; + count = CountInsideZones(); + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = insideZones[i]; + ENUM_X_DIRECTION iDir = iOBFVG.GetDirection(); + bool isBullish = IsBullish(iDir); + + // + bool isBullishBreaked = + // + zBar.high < iOBFVG.ob.Lower() && + cBar.high < iOBFVG.ob.Lower() + // + ; + + // + bool isBearishBreaked = + // + zBar.low > iOBFVG.ob.Upper() && + cBar.low > iOBFVG.ob.Upper() + // + ; + + // + bool isBreaked = + isBullish + ? isBullishBreaked + : isBearishBreaked; + + // + if (isBreaked) + { + // + idx = FindIndex( + iOBFVG, + breakedZones // + ); + has = IsValidIndex(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iOBFVG, + breakedZones // + ); + } + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + insideZones, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Detect Breaked Boxes ... + has = HasInsideBoxes(); + if (has) + { + // + int mustRemove[]; + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = insideBoxes[i]; + ENUM_X_DIRECTION iDir = iBox.dir; + bool isBullish = iBox.IsBullish(); + + // + bool isBullishBreaked = + // + zBar.high < iBox.lower && + cBar.high < iBox.lower + // + ; + + // + bool isBearishBreaked = + // + zBar.low > iBox.upper && + cBar.low > iBox.upper + // + ; + + // + bool isBreaked = + isBullish + ? isBullishBreaked + : isBearishBreaked; + + // + if (isBreaked) + { + // + idx = FindIndex( + iBox, + breakedBoxes // + ); + has = IsValidIndex(idx); + if (!has) + { + // + Add( + i, + mustRemove // + ); + + // + AddRef( + iBox, + breakedBoxes // + ); + } + } + } + + // + has = HasChild(mustRemove); + if (has) + { + // + count = ArraySize(mustRemove); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + insideBoxes, + mustRemove[i], + 1 // + ); + } + } + + // + Clean(mustRemove); + } + + // + // Cleanup Resource ... + + // + zBar.Clean(); + cBar.Clean(); + } + + // + bool HasSupplyZone() + { + return supplyZone != NULL && + supplyZone.IsValid(); + } + + // + bool HasDemandZone() + { + return demandZone != NULL && + demandZone.IsValid(); + } + + // + bool HasSupplyZones() + { + return HasChild(supplyZones); + } + + // + int CountSupplyZones() + { + return ArraySize(supplyZones); + } + + // + bool HasDemandZones() + { + return HasChild(demandZones); + } + + // + int CountDemandZones() + { + return ArraySize(demandZones); + } + + // + bool HasSupportZones() + { + return HasChild(supportZones); + } + + // + int CountSupportZones() + { + return ArraySize(supportZones); + } + + // + bool HasResistanceZones() + { + return HasChild(resistanceZones); + } + + // + int CountResistanceZones() + { + return ArraySize(resistanceZones); + } + + // + bool HasWaitingZones() + { + return HasChild(waitingZones); + } + + // + int CountWaitingZones() + { + return ArraySize(waitingZones); + } + + // + bool HasInsideZones() + { + return HasChild(insideZones); + } + + // + int CountInsideZones() + { + return ArraySize(insideZones); + } + + // + bool HasBreakedZones() + { + return HasChild(breakedZones); + } + + // + int CountBreakedZones() + { + return ArraySize(breakedZones); + } + + // + bool HasConsolidationZones() + { + return HasChild(consolidationZones); + } + + // + int CountConsolidationZones() + { + return ArraySize(consolidationZones); + } + + // + bool HasInsideBoxes() + { + return HasChild(insideBoxes); + } + + // + int CountInsideBoxes() + { + return ArraySize(insideBoxes); + } + + // + bool HasBreakedBoxes() + { + return HasChild(breakedBoxes); + } + + // + int CountBreakedBoxes() + { + return ArraySize(breakedBoxes); + } + + // + // + // + + // + bool IsDestroyed( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL cBar; + result = bar.GetPreviousBar(cBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + bool isSupplyZoneBreaked = + // + bar.low > supplyZone.Upper() && + cBar.low > supplyZone.Upper() + // + ; + + // + bool isDemandZoneBreaked = + // + bar.high < demandZone.Lower() && + cBar.high < demandZone.Lower() + // + ; + + // + bar.Clean(); + cBar.Clean(); + + // + result = isSupplyZoneBreaked || + isDemandZoneBreaked; + + // + return result; + } + + // + bool DetectPriority( + ENUM_X121SMC_XWZ_PRIORITY &priority, + ENUM_X_DIRECTION forDir, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + priority = X121SMC_XWZ_PRIORITY_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + if (bar.high < supplyZone.Upper() && + bar.low > supplyZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_NONE + : X121SMC_XWZ_PRIORITY_STRONG_HIGH; + } + else if (bar.high < supplyZone.Lower() && + bar.low > quarter1) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_WEAK + : X121SMC_XWZ_PRIORITY_HIGH; + } + else if (bar.high < quarter1 && + bar.low > quarter2) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_LOW + : X121SMC_XWZ_PRIORITY_REGULAR; + } + else if (bar.high < quarter2 && + bar.low > quarter3) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_REGULAR + : X121SMC_XWZ_PRIORITY_LOW; + } + else if (bar.high < quarter3 && + bar.low > demandZone.Upper()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_HIGH + : X121SMC_XWZ_PRIORITY_WEAK; + } + else if (bar.high < demandZone.Upper() && + bar.low > demandZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_STRONG_HIGH + : X121SMC_XWZ_PRIORITY_NONE; + } + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE && + priority != X121SMC_XWZ_PRIORITY_WEAK; + + // + bar.Clean(); + + // + return result; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasSupplyZone(); + if (has) + { + supplyZone.To(value); + } + + // + has = HasDemandZone(); + if (has) + { + demandZone.To(value); + } + + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } + } + + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } + } + + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + supportZones[i].To(value); + } + } + + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + resistanceZones[i].To(value); + } + } + + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + waitingZones[i].UpdateTo(value); + } + } + + // + has = HasInsideZones(); + if (has) + { + // + count = CountInsideZones(); + for (int i = 0; i < count; i++) + { + insideZones[i].UpdateTo(value); + } + } + + // + // has = HasBreakedZones(); + // if (has) + // { + // // + // count = CountBreakedZones(); + // for (int i = 0; i < count; i++) + // { + // breakedZones[i].UpdateTo(value); + // } + // } + + // + has = HasInsideBoxes(); + if (has) + { + // + count = CountInsideBoxes(); + for (int i = 0; i < count; i++) + { + insideBoxes[i].to = value; + } + } + + // + // has = HasBreakedBoxes(); + // if (has) + // { + // // + // count = CountBreakedBoxes(); + // for (int i = 0; i < count; i++) + // { + // insideBoxes[i].to = value; + // } + // } + + // + } + + // + void Draw( + XCPOIDrawer *drawer, + bool drawWaitingZones = true, + bool drawInsideZones = false, + bool drawBreakedZones = false, + bool drawSupplyZone = false, + bool drawDemandZone = false, + bool drawSupplyZones = false, + bool drawDemandZones = false, + bool drawSupportZones = false, + bool drawResistanceZones = false // + ) + { + // + if (drawer == NULL) + { + return; + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + ulong chartID = drawer.ChartIdentification(); + int subWindow = drawer.SubWindowIdentification(); + color bullishColor = drawer.BarBullishColor(); + color bearishColor = drawer.BarBearishColor(); + + // + // Supply Zone ... + if (drawSupplyZone) + { + // + has = HasSupplyZone(); + if (has) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Demand Zone ... + if (drawDemandZone) + { + // + has = HasDemandZone(); + if (has) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // + // + + // + // Supply Zones ... + if (drawSupplyZones) + { + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Demand Zones ... + if (drawDemandZones) + { + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Support Zones ... + if (drawSupportZones) + { + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = drawer.CreateSupportZone( + supportZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // Resistance Zones ... + if (drawResistanceZones) + { + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = drawer.CreateResistanceZone( + resistanceZones[i], + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + } + + // + // + // + + // + // Waiting Zones ... + if (drawWaitingZones) + { + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + waitingZones[i], + objects // + ); + has = IsValidSize(objectsCount); + if (has) + { + // + for (int j = 0; j < objectsCount; j++) + { + mWaitingZoneObjects.Add(objects[j]); + } + } + } + } + } + + // + // Inside Zones ... + if (drawInsideZones) + { + // + // Zones ... + has = HasInsideZones(); + if (has) + { + // + count = CountInsideZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + insideZones[i], + objects // + ); + + // + has = IsValidSize(objectsCount); + if (has) + { + // + for (int i = 0; i < objectsCount; i++) + { + mInsideZoneObjects.Add(objects[i]); + } + } + } + } + + // // + // // Boxes ... + // has = HasInsideBoxes(); + // if (has) + // { + // // + // count = CountInsideBoxes(); + // for (int i = 0; i < count; i++) + // { + // // + // XCBoxObject *object; + // bool isCreated = drawer.DrawBox( + // insideBoxes[i], + // object // + // ); + + // // + // if (isCreated) + // { + // mInsideZoneObjects.Add(object); + // } + // } + // } + } + + // + // Breaked Zones ... + if (drawBreakedZones) + { + // + has = HasBreakedZones(); + if (has) + { + // + count = CountBreakedZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *objects[]; + int objectsCount = drawer.DrawOBFVG( + breakedZones[i], + objects // + ); + + // + has = IsValidSize(objectsCount); + if (has) + { + // + for (int i = 0; i < objectsCount; i++) + { + mBreakedZoneObjects.Add(objects[i]); + } + } + } + } + + // // + // // Boxes ... + // has = HasBreakedBoxes(); + // if (has) + // { + // // + // count = CountBreakedBoxes(); + // for (int i = 0; i < count; i++) + // { + // // + // XCBoxObject *object; + // bool isCreated = drawer.DrawBox( + // breakedBoxes[i], + // object // + // ); + + // // + // if (isCreated) + // { + // mInsideZoneObjects.Add(object); + // } + // } + // } + } + + // + // + // + + // + // Quarters ... + has = IsValid(); + if (has) + { + // + double zoneUpper = supplyZone.Upper(); + double upper = supplyZone.Lower(); + + // + double lower = demandZone.Upper(); + double zoneLower = demandZone.Lower(); + + // + string prefix = "X121WZone_" + symbol + "_" + ToString(period); + + // + // Zone Upper ... + CChartObjectHLine *zoneUpperLine; + zoneUpperLine = new CChartObjectHLine(); + isCreated = zoneUpperLine.Create( + chartID, + prefix + "_ZoneTop", + subWindow, + zoneUpper // + ); + if (isCreated) + { + // + zoneUpperLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneUpperLine); + } + + // + // Zone Lower ... + CChartObjectHLine *zoneLowerLine; + zoneLowerLine = new CChartObjectHLine(); + isCreated = zoneLowerLine.Create( + chartID, + prefix + "_ZoneDown", + subWindow, + zoneLower // + ); + if (isCreated) + { + // + zoneLowerLine.Color(clrRed); + + // + mWaitingZoneObjects.Add(zoneLowerLine); + } + + // + // Upper ... + CChartObjectHLine *upperLine; + upperLine = new CChartObjectHLine(); + isCreated = upperLine.Create( + chartID, + prefix + "_Upper", + subWindow, + upper // + ); + if (isCreated) + { + // + upperLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(upperLine); + } + + // + // Lower ... + CChartObjectHLine *lowerLine; + lowerLine = new CChartObjectHLine(); + isCreated = lowerLine.Create( + chartID, + prefix + "_Lower", + subWindow, + lower // + ); + if (isCreated) + { + // + lowerLine.Color(clrLime); + + // + mWaitingZoneObjects.Add(lowerLine); + } + + // + // Quarters ... + + // + // Quarter 1 ... + CChartObjectHLine *q1Line; + q1Line = new CChartObjectHLine(); + isCreated = q1Line.Create( + chartID, + prefix + "_Q1", + subWindow, + quarter1 // + ); + if (isCreated) + { + // + q1Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q1Line); + } + + // + // Quarter 2 ... + CChartObjectHLine *q2Line; + q2Line = new CChartObjectHLine(); + isCreated = q2Line.Create( + chartID, + prefix + "_Q2", + subWindow, + quarter2 // + ); + if (isCreated) + { + // + q2Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q2Line); + } + + // + // Quarter 3 ... + CChartObjectHLine *q3Line; + q3Line = new CChartObjectHLine(); + isCreated = q3Line.Create( + chartID, + prefix + "_Q3", + subWindow, + quarter3 // + ); + if (isCreated) + { + // + q3Line.Color(clrYellow); + + // + mWaitingZoneObjects.Add(q3Line); + } + } + } + + // +}; + +// +// Definitions ... +struct X121SMCStrategyXWZSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double reward; + double amountPercent; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + double sls[]; + double targets[]; + + // + XBoxZone signalBox; + + // + ENUM_X121SMC_XWZ_PRIORITY priority; + ENUM_X121SMC_XWZ_PROVIDERS provider; + + // + // Constructor ... + X121SMCStrategyXWZSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + + // + ZeroMemory(this); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + reward = 0; + amountPercent = 0; + + // + Clean(sls); + Clean(targets); + signalBox.Clean(); + + // + provider = X121SMC_XWZ_PROVIDER_NONE; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + } + + // +}; + +// +// Extension Functions ... + +/** + * Check an XOBFVG instance has Required Conditions ... + * + * @param zone: XOBFVG instance ... + * @param state: XPOIState instance ... + * @param conditions: X121Conditions instance ... + * + * @return ( bool ) + */ +bool DetectSelectedZoneConditions( + bool &isReversal, + XOBFVG &zone, + XPOIState &state, + X121Conditions &conditions // +) +{ + // + bool result = false; + + // + isReversal = false; + + // + result = + zone.IsValid() && + state.IsValid() && + state.HasChild(); + if (!result) + { + return result; + } + + // + bool isBullish = zone.IsBullish(); + bool isBearish = zone.IsBearish(); + + // + bool isBullishTrend = conditions.isTrendBullish || + conditions.isTrendSwitchedToBullish; + bool isBearishTrend = conditions.isTrendBearish || + conditions.isTrendSwitchedToBearish; + + // + double bullishScore = 0; + double bearishScore = 0; + double scoreMultiplier = 1.5; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + + // + bool isBullishScorePassed = bullishScore > 0 && + bearishScore >= 0 && + bullishScore > bearishScore * scoreMultiplier; + + // + bool isBearishScorePassed = bearishScore > 0 && + bullishScore >= 0 && + bearishScore > bullishScore * scoreMultiplier; + + // + // VWap ... + + // + double vwapFast = conditions.vwapFastBuffer[0]; + double vwapMid = conditions.vwapMidBuffer[0]; + double vwapSlow = conditions.vwapSlowBuffer[0]; + + // + bool isVWapInside = + // + vwapFast > zone.ob.Lower() && + vwapFast < zone.ob.Upper() + // + && + vwapMid > zone.ob.Lower() && + vwapMid < zone.ob.Upper() + // + ; + + // + bool isVWapBullish = + // + (conditions.isVWapBullishState && + conditions.isVWapSwitchedToBullishOrdered) + // + || + // + (conditions.isVWapBullishOrdered && + conditions.isVWapSwitchedToBullishState) + // + ; + + // + bool isVWapBearish = + // + (conditions.isVWapBearishState && + conditions.isVWapSwitchedToBearishOrdered) + // + || + // + (conditions.isVWapBearishOrdered && + conditions.isVWapSwitchedToBearishState) + // + ; + + // + // X3Ma ... + + // + double x3maFast = conditions.x3maFastBuffer[0]; + double x3maMid = conditions.x3maMidBuffer[0]; + double x3maSlow = conditions.x3maSlowBuffer[0]; + + // + bool isX3MaInside = + // + x3maFast > zone.ob.Lower() && + x3maFast < zone.ob.Upper() + // + && + x3maMid > zone.ob.Lower() && + x3maMid < zone.ob.Upper() + // + ; + + // + bool isX3MaBullish = + // + (conditions.isX3MaBullishState && + conditions.isX3MaSwitchedToBullishOrdered) + // + || + // + (conditions.isX3MaBullishOrdered && + conditions.isX3MaSwitchedToBullishState) + // + ; + + // + bool isX3MaBearish = + // + (conditions.isX3MaBearishState && + conditions.isX3MaSwitchedToBearishOrdered) + // + || + // + (conditions.isX3MaBearishOrdered && + conditions.isX3MaSwitchedToBearishState) + // + ; + + // + // + // + + // + bool isInside = + // + isVWapInside || + isX3MaInside + // + ; + + // + bool isVWap3MaBullish = + isVWapBullish || + isX3MaBullish; + + // + bool isVWap3MaBearish = + isVWapBearish || + isX3MaBearish; + + // + // + // + + // + bool isDirectionalBullishPassed = + // + isInside && + isBullish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isDirectionalBearishPassed = + // + isInside && + isBearish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isDirectionalPassed = + isDirectionalBullishPassed || + isDirectionalBearishPassed; + + // + bool isReversalBullishPassed = + // + isInside && + isBullish && + isBearishTrend && + isVWap3MaBearish && + isBearishScorePassed + // + ; + + // + bool isReversalBearishPassed = + // + isInside && + isBearish && + isBullishTrend && + isVWap3MaBullish && + isBullishScorePassed + // + ; + + // + bool isReversalPassed = isReversalBullishPassed || + isReversalBearishPassed; + + // + result = isReversalPassed || + isDirectionalPassed; + + // + if (result) + { + isReversal = isReversalPassed; + } + + // + return result; +} + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + XOBFVG tmpZones[]; + + // + // Based On Waiting Zones ... + has = workingZone.HasWaitingZones(); + if (has) + { + // + Copy( + workingZone.waitingZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Breaked Zones ... + has = workingZone.HasBreakedZones(); + if (has) + { + Copy( + workingZone.breakedZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +/** + * Detect Targets Based on Selected Zone for Specified type of Directions ... + * + * @param targets: double Collection ... + * @param selectedZone: XBoxZone instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * + * @return ( bool ) + */ +bool DetectSelectedZonesTargets( + double &targets[], + XBoxZone &selectedZone, + ENUM_X_DIRECTION forDir, + ENUM_X121SMC_XWZ_PRIORITY forPriority, + X121SMCStrategyXWZWorkingZone &workingZone, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + Clean(targets); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() && + forPriority != X121SMC_XWZ_PRIORITY_NONE + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + XOBFVG tmpZones[]; + + // + // Based On Waiting Zones ... + has = workingZone.HasWaitingZones(); + if (has) + { + // + Copy( + workingZone.waitingZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Breaked Zones ... + has = workingZone.HasBreakedZones(); + if (has) + { + Copy( + workingZone.breakedZones, + tmpZones // + ); + + // + while (HasChild(tmpZones)) + { + // + XOBFVG iOBFVG; + + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + double iTarget = + isBullish + ? iOBFVG.ob.Lower() + : iOBFVG.ob.Upper(); + + // + has = + isBullish + ? cBar.high < iTarget + : cBar.low > iTarget; + + // + if (has) + { + // + Add( + iTarget, + targets // + ); + } + + // + iOBFVG.Clean(); + } + + // + Clean(tmpZones); + } + + // + // Based On Priority ... + has = forPriority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (forPriority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + + // + result = HasChild(targets); + + // + // Cleanup ... + cBar.Clean(); + Clean(tmpZones); + + // + return result; +} + +/** + * Detect SL Candidates Based on Selected Zone for Specified type of Directions ... + * + * @param sls: double Collection ... + * @param selectedZone: XOBFVG instance, selected Zone ... + * @param forDir: ENUM_X_DIRECTION specified Position Direction ... + * @param workingZone: X121SMCStrategyXWZWorkingZone instance, Specified Working Zone ... + * @param barIndex: int Specified Bar Index ... + * @param maxAllowedSLDistanceInPoint: doube max Allowe SL distance ... + * + * @return ( bool ) + */ +bool DetectSelectedZoneSLCandidates( + double &sls[], + XOBFVG &selectedZone, + ENUM_X_DIRECTION forDir, + X121SMCStrategyXWZWorkingZone &workingZone, + X121Conditions &conditions, + int barIndex = 0, + double maxAllowedSLDistanceInPoint = 300 // +) +{ + // + bool result = false; + + // + Clean(sls); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex++; + } + + // + result = + // + selectedZone.IsValid() && + HasDirection(forDir) && + workingZone.IsValid() + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + double pivot = + isBullish + ? selectedZone.ob.Lower() + : selectedZone.ob.Upper(); + double points = GetPoints(workingZone.symbol); + + // + XOHCL cBar; + result = cBar.Init( + workingZone.symbol, + workingZone.period, + barIndex // + ); + if (!result) + { + // + cBar.Clean(); + return result; + } + + // + int idx = -1; + bool has = false; + + // + double pvSL = isBullish + ? conditions.valesBuffer[0] + : conditions.peaksBuffer[1]; + + // + Add( + pvSL, + sls // + ); + + // + // Based On Passed Bars ... + // XOHCL passedBar; + // bool isPassed = false; + // bool isBodyState = false; + // ENUM_X_DIRECTION passedDir = selectedZone.GetDirection(); + + // // + // // Started Bar ... + // isPassed = selectedZone.ob.IsStarted( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Activation Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Worked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // // Breaked Bar ... + // passedBar.Clean(); + // isPassed = selectedZone.ob.IsActivated( + // passedDir, + // passedBar, + // isBodyState // + // ); + // if (isPassed) + // { + // // + // double iSL = + // isBullish + // ? passedBar.low + // : passedBar.high; + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // + // Based On Consolidation Zones ... + has = workingZone.HasConsolidationZones(); + if (has) + { + // + XConsolidationZone tmpZones[]; + Copy( + workingZone.consolidationZones, + tmpZones // + ); + XConsolidationZone selectedConsolidationZone; + + // + while (HasChild(tmpZones)) + { + // + idx = GetYoungest(tmpZones); + if (!IsValidIndex(idx)) + { + break; + } + + // + XConsolidationZone iZone = tmpZones[idx]; + + // + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + has = + !selectedConsolidationZone.IsValid() + ? isBullish + ? cBar.low < iZone.upper + : cBar.high < iZone.lower + : isBullish + ? selectedConsolidationZone.lower < iZone.lower + : selectedConsolidationZone.upper > iZone.upper; + if (has) + { + // + selectedConsolidationZone = iZone; + iZone.Clean(); + break; + } + + // + iZone.Clean(); + } + + // + Clean(tmpZones); + has = selectedConsolidationZone.IsValid(); + if (has) + { + // + double iSL = + isBullish + ? selectedConsolidationZone.lower + : selectedConsolidationZone.upper; + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + } + + // + // Based On Supply and Demand Zones ... + + // + // Demand Zones ... + has = workingZone.HasDemandZones(); + if (has) + { + // + XCDemandZone *tmpZones[]; + Copy( + workingZone.demandZones, + tmpZones // + ); + XCDemandZone *selectedDemand = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetLowest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCDemandZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + isBullish + ? IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedDemand == NULL + ? true + : isBullish + ? selectedDemand.Lower() < iZone.Lower() + : selectedDemand.Upper() > iZone.Upper(); + if (!has) + { + continue; + } + + // + selectedDemand = iZone; + } + + // + has = selectedDemand != NULL; + if (has) + { + // + double iSL = + isBullish + ? selectedDemand.Lower() + : selectedDemand.Upper(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedDemand); + } + + // + // Support Zones ... + // has = workingZone.HasSupportZones(); + // if (has) + // { + // // + // XCSupportZone *tmpZones[]; + // Copy( + // workingZone.supportZones, + // tmpZones // + // ); + // XCSupportZone *selectedSupport = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetLowest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCSupportZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // isBullish + // ? IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedSupport == NULL + // ? true + // : isBullish + // ? selectedSupport.Lower() < iZone.Lower() + // : selectedSupport.Upper() > iZone.Upper(); + // if (!has) + // { + // continue; + // } + + // // + // selectedSupport = iZone; + + // // + // } + + // // + // has = selectedSupport != NULL; + // if (has) + // { + // // + // double iSL = isBullish + // ? selectedSupport.Lower() + // : selectedSupport.Upper(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedSupport); + // } + + // + // Supply Zones ... + has = workingZone.HasSupplyZones(); + if (has) + { + // + XCSupplyZone *tmpZones[]; + Copy( + workingZone.supplyZones, + tmpZones // + ); + XCSupplyZone *selectedSupply = NULL; + + // + while (HasChild(tmpZones)) + { + // + idx = GetHighest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XCSupplyZone *iZone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + // Validate Zone ... + has = + !isBullish + ? IsAboveDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ) + : IsBelowDiff( + iZone, + selectedZone.ob, + true // Ignore Inside ... + ); + if (!has) + { + continue; + } + + // + has = + selectedSupply == NULL + ? true + : !isBullish + ? selectedSupply.Upper() > iZone.Upper() + : selectedSupply.Lower() < iZone.Lower(); + if (!has) + { + continue; + } + + // + selectedSupply = iZone; + + // + } + + // + has = selectedSupply != NULL; + if (has) + { + // + double iSL = + !isBullish + ? selectedSupply.Upper() + : selectedSupply.Lower(); + double iSLDiff = MathAbs(iSL - pivot); + has = + iSLDiff > 0 && + iSLDiff <= maxAllowedSLDistanceInPoint * points; + if (has) + { + // + Add( + iSL, + sls // + ); + } + } + + // + Clean(tmpZones); + ZeroMemory(selectedSupply); + } + + // + // Resistance Zones ... + // has = workingZone.HasDemandZones(); + // if (has) + // { + // // + // XCResistanceZone *tmpZones[]; + // Copy( + // workingZone.resistanceZones, + // tmpZones // + // ); + // XCResistanceZone *selectedResistance = NULL; + + // // + // while (HasChild(tmpZones)) + // { + // // + // idx = GetHighest(tmpZones); + // has = IsValidIndex(idx); + // if (!has) + // { + // break; + // } + + // // + // XCResistanceZone *iZone = tmpZones[idx]; + // ArrayRemove( + // tmpZones, + // idx, + // 1 // + // ); + + // // + // // Validate Zone ... + // has = + // !isBullish + // ? IsAboveDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ) + // : IsBelowDiff( + // iZone, + // selectedZone.ob, + // true // Ignore Inside ... + // ); + // if (!has) + // { + // continue; + // } + + // // + // has = + // selectedResistance == NULL + // ? true + // : !isBullish + // ? selectedResistance.Upper() < iZone.Upper() + // : selectedResistance.Lower() > iZone.Lower(); + // if (!has) + // { + // continue; + // } + + // // + // selectedResistance = iZone; + + // // + // } + + // // + // has = selectedResistance != NULL; + // if (has) + // { + // // + // double iSL = + // !isBullish + // ? selectedResistance.Upper() + // : selectedResistance.Lower(); + // double iSLDiff = MathAbs(iSL - pivot); + // has = + // iSLDiff > 0 && + // iSLDiff <= maxAllowedSLDistanceInPoint * points; + // if (has) + // { + // // + // Add( + // iSL, + // sls // + // ); + // } + // } + + // // + // Clean(tmpZones); + // ZeroMemory(selectedResistance); + // } + + // + // Cleanp Resources ... + + // + cBar.Clean(); + // passedBar.Clean(); + result = HasChild(sls); + + // + return result; +} + + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib.mq5 b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib.mq5 new file mode 100644 index 0000000..dd8835d --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-121.smc.xwz.signal.lib.mq5 @@ -0,0 +1,1582 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +enum ENUM_X121SMC_XWZ_PROVIDERS +{ + X121SMC_XWZ_PROVIDER_NONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_CHOCH, + X121SMC_XWZ_PROVIDER_PRICE_INSIDE_ZONE, +}; + +// +enum ENUM_X121SMC_XWZ_PRIORITY +{ + X121SMC_XWZ_PRIORITY_NONE, + X121SMC_XWZ_PRIORITY_WEAK, + X121SMC_XWZ_PRIORITY_LOW, + X121SMC_XWZ_PRIORITY_REGULAR, + X121SMC_XWZ_PRIORITY_HIGH, + X121SMC_XWZ_PRIORITY_STRONG_HIGH, +}; + +// +struct X121SMCStrategyXWZWorkingZone +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + + // + double quarter1; + double quarter2; + double quarter3; + + // + XOBFVG orderFlow[]; + XOBFVGPivot swings[]; + XOBFVG brokenOrderFlow[]; + CChartObjectTrend *orderFlowTrend; + + // + XCSupplyZone *supplyZones[]; + XCDemandZone *demandZones[]; + + // + // Constructor ... + X121SMCStrategyXWZWorkingZone() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + quarter1 = 0; + quarter2 = 0; + quarter3 = 0; + + // + symbol = NULL; + period = NULL; + + // + Clean(orderFlow); + Clean(brokenOrderFlow); + + // + Clean(swings); + ZeroMemory(supplyZone); + ZeroMemory(demandZone); + + // + if (orderFlowTrend != NULL) + { + orderFlowTrend.Delete(); + } + ZeroMemory(orderFlowTrend); + + // + ZeroMemory(this); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + // + quarter1 > 0 && + quarter2 > 0 && + quarter3 > 0 && + HasSupplyZone() && + HasDemandZone() && + quarter1 > quarter2 && + quarter2 > quarter3 + // + ; + + // + return result; + } + + // + bool HasSupplyZone() + { + return supplyZone != NULL && + supplyZone.IsValid(); + } + + // + bool HasDemandZone() + { + return demandZone != NULL && + demandZone.IsValid(); + } + + // + // + // + + // + bool HasOrderFlow() + { + // + bool result = false; + + // + result = IsValid() && + HasChild(orderFlow); + + // + return result; + } + + // + bool HasOrderFlow( + ENUM_X_DIRECTION &orderFlowDir // + ) + { + // + bool result = false; + + // + result = IsValid() && + HasChild(orderFlow); + if (result) + { + orderFlowDir = orderFlow[0].GetDirection(); + } + + // + return result; + } + + // + int CountOrderFlow() + { + return ArraySize(orderFlow); + } + + // + int GetSwings( + XOBFVGPivot &pivots[] // + ) + { + // + int result = 0; + + // + Clean(pivots); + + // + int count = 0; + bool has = false; + + // + has = HasOrderFlow(); + if (!has) + { + return result; + } + + // + count = CountOrderFlow(); + for (int i = 0; i < count; i++) + { + // + XOBFVGPivot iPivots[]; + int iPivotsCount = orderFlow[i] + .GetSwings(iPivots); + bool hasPivots = IsValidSize(iPivotsCount); + if (hasPivots) + { + // + Copy( + iPivots, + pivots, + false // + ); + } + + // + Clean(iPivots); + } + + // + result = ArraySize(pivots); + + // + return result; + } + + // + double GetOrderFlowTrendLinePrice( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + if (!IsValid() || + !HasOrderFlow() || + orderFlowTrend == NULL) + { + return result; + } + + // + datetime time = iTime( + symbol, + forPeriod, + barIndex // + ); + + // + result = ObjectGetValueByTime( + orderFlowTrend.ChartId(), + orderFlowTrend.Name(), + time // + ); + + // + return result; + } + + // + int DetectOrderFlow( + string forSymbol, + ENUM_TIMEFRAMES forPeriod, + ENUM_X_DIRECTION &orderFlowDir, + XPOIState <fState, + XPOIState &htfState, + XPOIState &mtfState, + XPOIState &stfState // + ) + { + // + int result = 0; + + // + Clean(orderFlow); + orderFlowDir = X_DIRECTION_NONE; + + // + bool isValid = + // + IsValid(forSymbol) && + IsValid(forPeriod) && + ltfState.HasChild() && + htfState.HasChild() && + mtfState.HasChild() && + stfState.HasChild() + // + ; + if (!isValid) + { + return result; + } + + // + // Find Working Zone ... + bool hasWorkingZone = IsValid(); + if (!hasWorkingZone) + { + // + symbol = forSymbol; + period = forPeriod; + + // + int idx = -1; + bool has = false; + + // + has = ltfState.HasSupplyZones(); + if (has) + { + // + idx = GetHighest(ltfState.supplyZones); + if (IsValidIndex(idx)) + { + supplyZone = ltfState.supplyZones[idx]; + } + } + + // + has = ltfState.HasDemandZones(); + if (has) + { + // + idx = GetLowest(ltfState.demandZones); + if (IsValidIndex(idx)) + { + demandZone = ltfState.demandZones[idx]; + } + } + + // + hasWorkingZone = HasSupplyZone() && + HasDemandZone(); + if (hasWorkingZone) + { + // + double upper = supplyZone.Lower(); + double lower = demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + quarter1 = upper - (1 * delta); + quarter2 = upper - (2 * delta); + quarter3 = upper - (3 * delta); + + // + hasWorkingZone = IsValid(); + } + } + + // + if (!hasWorkingZone) + { + return result; + } + + // + // Bullish OBFVGs ... + XOBFVG bullOBFVGs[]; + int bullOBFVGsCount = ExtractOBFVGZones( + htfState, + mtfState, + stfState, + bullOBFVGs, + X_DIRECTION_BULLISH, + NULL, // For Period ... + // + // Start ... + XZONE_STATE_PASSED, + true, // Force Body Out ... + // + // Activation ... + XZONE_STATE_PASSED, + true, // Force Body In ... + // + // Breaktion ... + XZONE_STATE_FAILED, + false, // Force Body In ... + // + // Works ... + XZONE_STATE_PASSED, + true, // Force Body Out ... + // + true, // Apply Sort ... + true, // From Filter ... + true, // Place Filter ... + // + true, // Ignore Inside in Place Filter ... + // + true, // Detect Inside OB POI(s) ... + true, // Detect Inside FVG POI(s) ... + true // Apply From Filter to Selected POI(s) ... + ); + bool hasBullOBFVGs = IsValidSize(bullOBFVGsCount); + + // + // Bearish OBFVGs ... + XOBFVG bearOBFVGs[]; + int bearOBFVGsCount = ExtractOBFVGZones( + htfState, + mtfState, + stfState, + bearOBFVGs, + X_DIRECTION_BEARISH, + NULL, // For Period ... + // + // Start ... + XZONE_STATE_PASSED, + true, // Force Body Out ... + // + // Activation ... + XZONE_STATE_PASSED, + true, // Force Body In ... + // + // Breaktion ... + XZONE_STATE_FAILED, + false, // Force Body In ... + // + // Works ... + XZONE_STATE_PASSED, + true, // Force Body Out ... + // + true, // Apply Sort ... + true, // From Filter ... + true, // Place Filter ... + // + true, // Ignore Inside in Place Filter ... + // + true, // Detect Inside OB POI(s) ... + true, // Detect Inside FVG POI(s) ... + true // Apply From Filter to Selected POI(s) ... + ); + bool hasBearOBFVGs = IsValidSize(bearOBFVGsCount); + + // + XOBFVG lastBroken; + bool hasBroken = false; + int idx = GetYoungest(brokenOrderFlow); + if (IsValidIndex(idx)) + { + // + lastBroken = brokenOrderFlow[idx]; + hasBroken = lastBroken.IsValid(); + } + + // + bool hasOrderFlow = hasBearOBFVGs || + hasBullOBFVGs; + if (hasOrderFlow) + { + // + // Vlidate ... + isValid = + // + (hasBullOBFVGs && + !hasBearOBFVGs && + bullOBFVGsCount >= 1) + // + || + // + (hasBearOBFVGs && + !hasBullOBFVGs && + bearOBFVGsCount >= 1) + // + ; + + // + if (isValid) + { + // + if (hasBullOBFVGs) + { + // + Copy( + bullOBFVGs, + orderFlow // + ); + } + else if (hasBearOBFVGs) + { + // + Copy( + bearOBFVGs, + orderFlow // + ); + } + + // + orderFlowDir = + hasBullOBFVGs + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + bool isPlacePassed = true; + if (hasBroken) + { + // + bool isBullish = IsBullish(orderFlowDir); + + // + idx = GetYoungest(orderFlow); + bool hasYounget = IsValidIndex(idx); + + // + isPlacePassed = + ArraySize(orderFlow) > 1 + ? true + : isBullish + ? (IsAbove( + orderFlow[idx].ob, + lastBroken.ob, + true // Ignore Inside ... + )) + : (IsBelow( + orderFlow[idx].ob, + lastBroken.ob, + true // Ignore Inside + )); + + // + Clean(brokenOrderFlow); + AddRef( + orderFlow[idx], + brokenOrderFlow // + ); + } + + // + if (!isPlacePassed) + { + // + Clean(orderFlow); + orderFlowDir = X_DIRECTION_NONE; + } + + // + result = ArraySize(orderFlow); + } + } + + // + Clean(bullOBFVGs); + Clean(bearOBFVGs); + + // + lastBroken.Clean(); + + // + if (IsValidSize(result)) + { + // + int count = GetSwings(swings); + bool has = count >= 2; + bool isBullish = IsBullish(orderFlowDir); + if (has) + { + // + // Get Max / Min ... + double max = 0; + double min = 0; + datetime maxAt = NULL; + datetime minAt = NULL; + for (int i = 0; i < count; i++) + { + // + XOBFVGPivot iPivot = swings[i]; + + // + if (!iPivot.IsValid()) + { + // + iPivot.Clean(); + continue; + } + + // + // Min ... + bool canSetMin = + min == 0 + ? true + : min > iPivot.value; + if (canSetMin) + { + // + minAt = iPivot.at; + min = iPivot.value; + } + + // + // Max ... + bool canSetMax = + max == 0 + ? true + : max < iPivot.value; + if (canSetMax) + { + // + maxAt = iPivot.at; + max = iPivot.value; + } + + // + iPivot.Clean(); + } + + // + double price1 = + isBullish + ? min + : max; + double price2 = + isBullish + ? max + : min; + datetime time1 = + isBullish + ? minAt + : maxAt; + datetime time2 = + isBullish + ? maxAt + : minAt; + + // + color clrTrend = clrNONE; + + // + string trendName = + "XORDFLW" + ToString(orderFlowDir) + "_" + "XTRNDL_" + + ToString(period) + "_" + + ToString(price1) + "_" + + ToString(price2) + "_"; + + // + orderFlowTrend = new CChartObjectTrend(); + has = orderFlowTrend.Create( + 0, + trendName, + 0, + time1, + price1, + time2, + price2 // + ); + + // + if (has) + { + // + orderFlowTrend.Width(1); + orderFlowTrend.Color(clrTrend); + orderFlowTrend.RayRight(true); + } + } + } + + // + return result; + } + + // + void AddOrderFlowItem( + XOBFVG &orderItem // + ) + { + // + ENUM_X_DIRECTION trend; + if (!HasOrderFlow(trend)) + { + return; + } + + // + bool isSameDir = orderItem + .GetDirection() == trend; + if (!isSameDir) + { + return; + } + + // + bool isBullish = IsBullish(trend); + + // + AddRef( + orderItem, + orderFlow // + ); + + // + Sort( + orderFlow, + trend, + true // Ignore Inside ... + ); + } + + // + bool IsDestroyed( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL cBar; + result = bar.GetPreviousBar(cBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + bool isSupplyZoneBreaked = + // + bar.low > supplyZone.Upper() && + cBar.low > supplyZone.Upper() + // + ; + + // + bool isDemandZoneBreaked = + // + bar.high < demandZone.Lower() && + cBar.high < demandZone.Lower() + // + ; + + // + bar.Clean(); + cBar.Clean(); + + // + result = isSupplyZoneBreaked || + isDemandZoneBreaked; + + // + return result; + } + + // + bool IsOrderFlowBreaked( + int &breakedIndex, + bool forceOBBreake = false, + bool forceFVGBreake = false, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + breakedIndex = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + ENUM_X_DIRECTION orderFlowDir; + result = HasOrderFlow(orderFlowDir); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + bool isBullish = IsBullish(orderFlowDir); + + // + int idx = + isBullish + ? GetHighest(orderFlow) + : GetLowest(orderFlow); + result = IsValidIndex(idx); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL obBreakerBar; + bool isOBBodyOut = false; + bool isOBBreaked = orderFlow[idx].ob.IsBreaked( + orderFlowDir, + obBreakerBar, + isOBBodyOut, + false, // Ignore Start ... + false, // Started Bar Body Out ... + forPeriod // + ); + + // + if (!isOBBreaked) + { + obBreakerBar.Clean(); + } + + // + XOHCL fvgBreakerBar; + bool isFVGBodyOut = false; + bool isFVGBreaked = orderFlow[idx].fvg.IsBreaked( + orderFlowDir, + fvgBreakerBar, + isFVGBodyOut, + false, // Ignore Start ... + true, // Started Bar Body Out ... + forPeriod // + ); + + // + if (!isFVGBreaked) + { + fvgBreakerBar.Clean(); + } + + // + isOBBreaked = + obBreakerBar.IsValid(); + + // + isFVGBreaked = + fvgBreakerBar.IsValid(); + + // + if ((forceOBBreake && forceFVGBreake) || + (!forceOBBreake && !forceFVGBreake)) + { + // + result = isOBBreaked || + isFVGBreaked; + } + else if (forceOBBreake) + { + result = isOBBreaked; + } + else if (forceFVGBreake) + { + result = isFVGBreaked; + } + + // + if (result) + { + breakedIndex = idx; + } + + // + bar.Clean(); + obBreakerBar.Clean(); + fvgBreakerBar.Clean(); + + // + return result; + } + + // + bool DetectPriority( + ENUM_X121SMC_XWZ_PRIORITY &priority, + ENUM_X_DIRECTION forDir, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + priority = X121SMC_XWZ_PRIORITY_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + if (bar.high < supplyZone.Upper() && + bar.low > supplyZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_NONE + : X121SMC_XWZ_PRIORITY_STRONG_HIGH; + } + else if (bar.high < supplyZone.Lower() && + bar.low > quarter1) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_WEAK + : X121SMC_XWZ_PRIORITY_HIGH; + } + else if (bar.high < quarter1 && + bar.low > quarter2) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_LOW + : X121SMC_XWZ_PRIORITY_REGULAR; + } + else if (bar.high < quarter2 && + bar.low > quarter3) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_REGULAR + : X121SMC_XWZ_PRIORITY_LOW; + } + else if (bar.high < quarter3 && + bar.low > demandZone.Upper()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_HIGH + : X121SMC_XWZ_PRIORITY_WEAK; + } + else if (bar.high < demandZone.Upper() && + bar.low > demandZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_STRONG_HIGH + : X121SMC_XWZ_PRIORITY_NONE; + } + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE && + priority != X121SMC_XWZ_PRIORITY_WEAK; + + // + bar.Clean(); + + // + return result; + } + + // + // + // + + // + bool HasSupplyZones() + { + return HasChild(supplyZones); + } + + // + int CountSupplyZones() + { + return ArraySize(supplyZones); + } + + // + bool HasDemandZones() + { + return HasChild(demandZones); + } + + // + int CountDemandZones() + { + return ArraySize(demandZones); + } + + // + int DetectSupplyZones( + XPOIState &state // + ) + { + // + int result = CountSupplyZones(); + + bool isValid = state.IsValid() && + state.HasSupplyZones(); + if (!isValid) + { + return result; + } + + // + XCSupplyZone *tmpZones[]; + Copy( + state.supplyZones, + tmpZones // + ); + int count = FilterZones( + // + tmpZones, + // + X_DIRECTION_BULLISH, + state.period, + NULL, + // + // Start ... + XZONE_STATE_IGNORED, + false, + // + // Activation ... + XZONE_STATE_IGNORED, + false, + // + // Breake ... + XZONE_STATE_FAILED, + false, + // + // Work ... + XZONE_STATE_IGNORED, + false, + // + true, // Apply Sore ... + true // Ignore Inside ... + ); + bool has = IsValidSize(count); + if (!has) + { + return result; + } + + // + int idx = -1; + while (HasChild(tmpZones)) + { + // + XCSupplyZone *iZone; + idx = GetHighest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + // + ZeroMemory(iZone); + continue; + } + + // + iZone = tmpZones[idx]; + + // + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + idx = FindIndex( + iZone, + supplyZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + ZeroMemory(iZone); + continue; + } + + // + Add( + iZone, + supplyZones // + ); + } + + // + int after = CountSupplyZones(); + result = after; + + // + return result; + } + + // + int DetectDemandZones( + XPOIState &state // + ) + { + // + int result = CountDemandZones(); + + bool isValid = state.IsValid() && + state.HasDemandZones(); + if (!isValid) + { + return result; + } + + // + XCDemandZone *tmpZones[]; + Copy( + state.demandZones, + tmpZones // + ); + int count = FilterZones( + // + tmpZones, + // + X_DIRECTION_BEARISH, + state.period, + NULL, + // + // Start ... + XZONE_STATE_IGNORED, + false, + // + // Activation ... + XZONE_STATE_IGNORED, + false, + // + // Breake ... + XZONE_STATE_FAILED, + false, + // + // Work ... + XZONE_STATE_IGNORED, + false, + // + true, // Apply Sore ... + true // Ignore Inside ... + ); + bool has = IsValidSize(count); + if (!has) + { + return result; + } + + // + int idx = -1; + while (HasChild(tmpZones)) + { + // + XCDemandZone *iZone; + idx = GetLowest(tmpZones); + has = IsValidIndex(idx); + if (!has) + { + // + ZeroMemory(iZone); + continue; + } + + // + iZone = tmpZones[idx]; + + // + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + idx = FindIndex( + iZone, + demandZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + ZeroMemory(iZone); + continue; + } + + // + Add( + iZone, + demandZones // + ); + } + + // + int after = CountDemandZones(); + result = after; + + // + return result; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasSupplyZone(); + if (has) + { + supplyZone.To(value); + } + + // + has = HasDemandZone(); + if (has) + { + demandZone.To(value); + } + + // + // Order Flow ... + ENUM_X_DIRECTION orderFlowDir; + has = HasOrderFlow(orderFlowDir); + if (has) + { + // + count = CountOrderFlow(); + for (int i = 0; i < count; i++) + { + orderFlow[i].UpdateTo(value); + } + } + + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } + } + + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } + } + + // + } +}; + +// +// Definitions ... +struct X121SMCStrategyXWZSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double reward; + double amountPercent; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + double targets[]; + + // + XOBFVG signalZone; + + // + ENUM_X121SMC_XWZ_PRIORITY priority; + ENUM_X121SMC_XWZ_PROVIDERS provider; + + // + // Constructor ... + X121SMCStrategyXWZSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + + // + ZeroMemory(this); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + reward = 0; + amountPercent = 0; + + // + Clean(targets); + signalZone.Clean(); + + // + provider = X121SMC_XWZ_PROVIDER_NONE; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-saherelm.x-poi.class.mq5 b/BKPS/14031218/Documents/BKP/x-saherelm.x-poi.class.mq5 new file mode 100644 index 0000000..be134d9 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-saherelm.x-poi.class.mq5 @@ -0,0 +1,4218 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOI +// Description: Provides Point of Interests ... +// - Swing Highs; +// - Swing Lows; +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +#include + +// +// Implementation ... + +// +// POI Detector Class ... +class XCPOIDetector : public XCBaseAlert +{ + // + public: + // + XCPOIDrawer *mDrawer; + + // + // Constructors ... + /** + * Create an Instance ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + */ + void XCPOIDetector( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + // + // Attach Required Properties ... + mSymbol = symbol; + mPeriod = period; + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + mSymbol, + mPeriod // + ); + + // + // Create Default Drawer Instance ... + mDrawer = new XCPOIDrawer(); + + // + // Apply Default Configurations ... + Default(); + } + + // + // Deconstructor ... + void ~XCPOIDetector() + { + Destroy(); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Retrieve Detector Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve Detector Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Get Max Number of POIs which holds ... + * + * @return ( int ) + */ + int MaxNumberOfPOIs() + { + return mMaxNumberOfPOIs; + } + + /** + * Set Max Number of POIs which holds ... + * 0 => Infinity ... + * + * @param value: Integer ... + */ + void MaxNumberOfPOIs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxNumberOfPOIs = value; + } + + /** + * Get Number of POI(s) which must Find at Initializations ... + * + * @return ( int ) + */ + int MaxNumberOfRequiredPOIs() + { + return mMaxNumberOfRequiredPOIs; + } + + /** + * Set Number of POI(s) which must Find at Initializations ... + * 2 is Default ... + * + * @param value: Integer ... + */ + void MaxNumberOfRequiredPOIs(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mMaxNumberOfRequiredPOIs = value; + } + + /** + * Check Is Locked or not ... + * + * @return ( bool ) + */ + bool IsLocked() + { + return mLock; + } + + // + // POI(s) Configs ... + + // + // Swings ... + + /** + * Get Swing Verification Range Length ... + * + * @return ( int ) + */ + int SwingRange() + { + return mSwingRange; + } + + /** + * Set Swing Verification Range Length ... + * + * @param value: Integer ... + */ + void SwingRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSwingRange = value; + } + + // + // Momentum Bars ... + + /** + * Get Momentum Bars must Extends Range ... + * + * @return ( int ) + */ + int MomentumBarExtendRange() + { + return mMomentumBarExtendRange; + } + + /** + * Set Momentum Bars must Extends Range ... + * + * @param value: Integer ... + */ + void MomentumBarExtendRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumBarExtendRange = value; + } + + /** + * Get Momentum Bars Body Percent ... + * + * @return ( double ) + */ + double MomentumBarBodyPercent() + { + return mMomentumBarBodyPercent; + } + + /** + * Set Momentum Bars Body Percent ... + * + * @param value: Double ... + */ + void MomentumBarBodyPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + mMomentumBarBodyPercent = value; + } + + // + // Rejection Bars ... + + /** + * Get Rejection Bars must Extends Range ... + * + * @return ( int ) + */ + int RejectionBarExtendRange() + { + return mRejectionBarExtendRange; + } + + /** + * Set Rejection Bars must Extends Range ... + * + * @param value: Integer ... + */ + void RejectionBarExtendRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRejectionBarExtendRange = value; + } + + /** + * Get Rejection Bars Shadow Percent ... + * + * @return ( double ) + */ + double RejectionBarShadowPercent() + { + return mRejectionBarShadowPercent; + } + + /** + * Set Rejection Bars Shadow Percent ... + * + * @param value: Double ... + */ + void RejectionBarShadowPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + mRejectionBarShadowPercent = value; + } + + // + // Support and Resistance Zone(s) ... + + /** + * Get Support and Resistance Range for Verification ... + * + * @return ( int ) + */ + int SupportAndResistanceRange() + { + return mSupportAndResistanceRange; + } + + /** + * Set Support and Resistance Range for Verification ... + * + * @param value: Integer ... + */ + void SupportAndResistanceRange(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mSupportAndResistanceRange = value; + } + + // + // Supply and Demand Zone(s) ... + + /** + * Get Supply and Demand Range Verifications ... + * + * @return ( int ) + */ + int SupplyAndDemandRange() + { + return mSupplyAndDemandRange; + } + + /** + * Set Supply and Demand Range Verifications ... + * + * @param value: Integer ... + */ + void SupplyAndDemandRange(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mSupplyAndDemandRange = value; + } + + // + // Order Blocks ... + + /** + * Get Order Blocks Detection Bars ... + * + * @return ( int ) + */ + int OrderBlocksSameBars() + { + return mOrderBlocksSameBars; + } + + /** + * Set Order Blocks Detection Bars ... + * + * @param value: Argument 1 + */ + void OrderBlocksSameBars(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mOrderBlocksSameBars = value; + } + + // + // Fair Value Gaps ... + + /** + * Get Fair Value Gaps Detection Same Bars ... + * + * @return ( int ) + */ + int FairValueGapsSameBars() + { + return mFairValueGapsSameBars; + } + + /** + * Set Fair Value Gaps Detection Same Bars ... + * + * @param value: Integer ... + */ + void FairValueGapsSameBars(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mFairValueGapsSameBars = value; + } + + // + // Ticks Zone ... + + /** + * Get Ticks Range Levels ... + * + * @return ( int ) + */ + int TicksRangeZoneLevel() + { + return mTicksRangeZoneLevel; + } + + /** + * Set Ticks Range Levels ... + * + * @param value: Integer ... + */ + void TicksRangeZoneLevel(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mTicksRangeZoneLevel = value; + } + + /** + * Get Ticks Range Zone Loopback Period ... + * + * @return ( int ) + */ + int TicksRangeZoneRange() + { + return mTicksRangeZoneRange; + } + + /** + * Set Ticks Range Zone Loopback Period ... + * + * @param value: Integer ... + */ + void TicksRangeZoneRange(int value) + { + // + if (value < 7) + { + value = 7; + } + + // + mTicksRangeZoneRange = value; + } + + // + // Actions ... + + /** + * Initialize POI Detector ... + */ + void Init() + { + DetectRequiredPOIs(); + } + + /** + * Update POI(s) ... + * + * @param state: an Array Refrence of ENUM_XPOI_EVENTS members ... + */ + int Update( + ENUM_XPOI_EVENTS &state[] // + ) + { + // + int result = 0; + + // + Clean(state); + + // + // Check Bar Tracker if Waits ... + if (!mBarTracker.IsNewBar()) + { + return result; + } + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + XOHCL zBar; + bool isInited = zBar.Init( + symbol, + period, + zIndex // + ); + if (!isInited) + { + return result; + } + + // + XOHCL cBar; + isInited = cBar.Init( + symbol, + period, + cIndex // + ); + if (!isInited) + { + return result; + } + + // + // POI Detecting ... + bool isDetected = false; + + // + // Swings ... + int iSwingRange = SwingRange(); + if (iSwingRange > 0) + { + // + XOHCL swingBar; + isInited = swingBar.Init( + symbol, + period, + zIndex + iSwingRange // + ); + if (isInited) + { + // + // Swing High ... + isDetected = DetectSwingHigh(swingBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SWING_HIGH_DETECTED; + XCSwing *param; + bool hasItem = GetLastItem( + param, + mSwingHighs // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Swing Low ... + isDetected = DetectSwingLow(swingBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SWING_LOW_DETECTED; + XCSwing *param; + bool hasItem = GetLastItem( + param, + mSwingLows // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + } + + // + // Bullish Momentum Bars ... + isDetected = DetectBullishMomentumBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_MOMENTUM_BAR_DETECTED; + XCMomentumBar *param; + bool hasItem = GetLastItem( + param, + mBullishMomentumBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Momentum Bars ... + isDetected = DetectBearishMomentumBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_MOMENTUM_BAR_DETECTED; + XCMomentumBar *param; + bool hasItem = GetLastItem( + param, + mBearishMomentumBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bullish Rejection Bars ... + isDetected = DetectBullishRejectionBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_REJECTION_BAR_DETECTED; + XCRejectionBar *param; + bool hasItem = GetLastItem( + param, + mBullishRejectionBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Rejection Bars ... + isDetected = DetectBearishRejectionBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_REJECTION_BAR_DETECTED; + XCRejectionBar *param; + bool hasItem = GetLastItem( + param, + mBearishRejectionBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Support and Resistance Zones ... + int supResRange = SupportAndResistanceRange(); + if (supResRange > 0) + { + // + XOHCL supResBar; + isInited = supResBar.Init( + symbol, + period, + zIndex + supResRange // + ); + if (isInited) + { + // + // Support Zones ... + isDetected = DetectSupportZone(supResBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SUPPORT_ZONE_DETECTED; + XCSupportZone *param; + bool hasItem = GetLastItem( + param, + mSupportZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Resistance Zones ... + isDetected = DetectResistanceZone(supResBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_RESISTANCE_ZONE_DETECTED; + XCResistanceZone *param; + bool hasItem = GetLastItem( + param, + mResistanceZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + } + + // + // Supply And Demand Zones ... + int supDemRange = SupplyAndDemandRange(); + if (supDemRange > 0) + { + // + // Supply Zone ... + isDetected = DetectSupplyZone(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SUPPLY_ZONE_DETECTED; + XCSupplyZone *param; + bool hasItem = GetLastItem( + param, + mSupplyZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Demand Zone ... + isDetected = DetectDemandZone(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_DEMAND_ZONE_DETECTED; + XCDemandZone *param; + bool hasItem = GetLastItem( + param, + mDemandZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Order Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Block ... + isDetected = DetectBullishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBullishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Order Block ... + isDetected = DetectBearishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBearishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Fair Value Gaps ... + int fvgSameBars = FairValueGapsSameBars(); + if (fvgSameBars > 0) + { + // + // Bullish Fair Value Gap ... + isDetected = DetectBullishFairValueGap(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_FVG_DETECTED; + XCFVG *param; + bool hasItem = GetLastItem( + param, + mBullishFairValueGaps // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Fair Value Gap ... + isDetected = DetectBearishFairValueGap(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_FVG_DETECTED; + XCFVG *param; + bool hasItem = GetLastItem( + param, + mBearishFairValueGaps // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Ticks Range Zone ... + int ticksLevels = TicksRangeZoneLevel(); + int ticksRange = TicksRangeZoneRange(); + if (ticksLevels > 0 && + ticksRange > 0) + { + // + isDetected = DetectTicksZoneRange(cBar); + if (isDetected) + { + } + } + + // + ValidatePOIs(cBar); + + // + CleanupUnusedPOIs(); + + // + mBarTracker.Waits(); + + // + result = ArraySize(state); + + // + return result; + } + + /** + * Destroy Class ... + */ + void Destroy() + { + // + DestroyPOIs(); + DestroySessions(); + DestroyEventListeners(); + + // + delete mDrawer; + delete mTicksZone; + + // + ZeroMemory(mDrawer); + ZeroMemory(mTicksZone); + } + + // + // Retrievers ... + + /** + * Get Current State of POIs ... + * + * @param state: XPOIState instance ... + */ + void GetState( + XPOIState &state // + ) + { + // + state.Clean(); + + // + state.symbol = mSymbol; + state.period = mPeriod; + state.time = TimeCurrent(); + + // + Copy( + mSwingHighs, + state.swingHighs // + ); + + // + Copy( + mSwingLows, + state.swingLows // + ); + + // + Copy( + mBullishMomentumBars, + state.bullishMomentumBars // + ); + + // + Copy( + mBearishMomentumBars, + state.bearishMomentumBars // + ); + + // + Copy( + mBullishRejectionBars, + state.bullishRejectionBars // + ); + + // + Copy( + mBearishRejectionBars, + state.bearishRejectionBars // + ); + + // + Copy( + mSupportZones, + state.supportZones // + ); + + // + Copy( + mResistanceZones, + state.resistanceZones // + ); + + // + Copy( + mSupplyZones, + state.supplyZones // + ); + + // + Copy( + mDemandZones, + state.demandZones // + ); + + // + Copy( + mBullishOrderBlocks, + state.bullishOrderBlocks // + ); + + // + Copy( + mBearishOrderBlocks, + state.bearishOrderBlocks // + ); + + // + Copy( + mBullishFairValueGaps, + state.bullishFairValueGaps // + ); + + // + Copy( + mBearishFairValueGaps, + state.bearishFairValueGaps // + ); + + // + state.ticksZone = mTicksZone; + + // + } + + // + // Event Listeners ... + + /** + * Add Event Listener ... + * + * @param listener: TOnPOIEvent instance ... + */ + void AddEventListener(TOnPOIEvent listener) + { + // + Add( + listener, + mEventListeners // + ); + } + + // + // Destroy ... + + /** + * Destroy Detected POI(s) ... + */ + void DestroyPOIs() + { + // + Clean(mSwingHighs); + Clean(mSwingLows); + + // + Clean(mBullishMomentumBars); + Clean(mBearishMomentumBars); + + // + Clean(mBullishRejectionBars); + Clean(mBearishRejectionBars); + + // + Clean(mSupportZones); + Clean(mResistanceZones); + + // + Clean(mSupplyZones); + Clean(mDemandZones); + + // + Clean(mBullishOrderBlocks); + Clean(mBearishOrderBlocks); + + // + Clean(mBullishFairValueGaps); + Clean(mBearishFairValueGaps); + } + + /** + * Destroy Added Sessions ... + */ + void DestroySessions() + { + } + + /** + * Destroy Rejistered Event Handlers ... + */ + void DestroyEventListeners() + { + Clean(mEventListeners); + } + + // + // Virtual Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Common ... + + // + MaxNumberOfPOIs(10); + MaxNumberOfRequiredPOIs(2); + + // + SwingRange(2); + + // + MomentumBarExtendRange(2); + MomentumBarBodyPercent(70); + + // + RejectionBarExtendRange(0); + RejectionBarShadowPercent(55); + + // + SupportAndResistanceRange(7); + + // + SupplyAndDemandRange(144); + + // + OrderBlocksSameBars(3); + + // + FairValueGapsSameBars(3); + + // + TicksRangeZoneLevel(10); + TicksRangeZoneRange(144); + } + + // + // Detector Functions ... + + /** + * Detect Swing High ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSwingHigh(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SwingRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSwingHigh( + bar, + range // + ); + if (result) + { + // + XCSwing *swing; + swing = new XCSwing(); + result = swing.Init( + bar, + X_POI_SWING_HIGH // + ); + + // + if (result) + { + // + Add( + swing, + mSwingHighs // + ); + } + } + + // + return result; + } + + /** + * Detect Swing Low ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSwingLow(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SwingRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSwingLow( + bar, + range // + ); + if (result) + { + // + XCSwing *swing; + swing = new XCSwing(); + result = swing.Init( + bar, + X_POI_SWING_LOW // + ); + + // + if (result) + { + // + Add( + swing, + mSwingLows // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Momentum Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishMomentumBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = MomentumBarExtendRange(); + double bodyPercent = MomentumBarBodyPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsMomentumBar( + bar, + dir, + extendRange, + bodyPercent // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (result) + { + // + XCMomentumBar *momentumBar; + momentumBar = new XCMomentumBar(); + result = momentumBar.Init(bar); + + // + if (result) + { + // + Add( + momentumBar, + mBullishMomentumBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Momentum Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishMomentumBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = MomentumBarExtendRange(); + double bodyPercent = MomentumBarBodyPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsMomentumBar( + bar, + dir, + extendRange, + bodyPercent // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (result) + { + // + XCMomentumBar *momentumBar; + momentumBar = new XCMomentumBar(); + result = momentumBar.Init(bar); + + // + if (result) + { + // + Add( + momentumBar, + mBearishMomentumBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Rejection Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishRejectionBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = RejectionBarExtendRange(); + double shadowPercent = RejectionBarShadowPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsRejectionBar( + bar, + dir, + extendRange, + shadowPercent // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (result) + { + // + XCRejectionBar *rejectionBar; + rejectionBar = new XCRejectionBar(); + result = rejectionBar.Init(bar); + + // + if (result) + { + // + Add( + rejectionBar, + mBullishRejectionBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Rejection Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishRejectionBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = RejectionBarExtendRange(); + double shadowPercent = RejectionBarShadowPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsRejectionBar( + bar, + dir, + extendRange, + shadowPercent // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (result) + { + // + XCRejectionBar *rejectionBar; + rejectionBar = new XCRejectionBar(); + result = rejectionBar.Init(bar); + + // + if (result) + { + // + Add( + rejectionBar, + mBearishRejectionBars // + ); + } + } + + // + return result; + } + + /** + * Detect Support Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSupportZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupportAndResistanceRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSupport( + bar, + range // + ); + if (result) + { + // + XCSupportZone *support; + support = new XCSupportZone(); + result = support.Init( + bar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + support.To(cTime); + + // + Add( + support, + mSupportZones // + ); + } + } + + // + return result; + } + + /** + * Detect Resistance Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectResistanceZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupportAndResistanceRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsResistance( + bar, + range // + ); + if (result) + { + // + XCResistanceZone *resistance; + resistance = new XCResistanceZone(); + result = resistance.Init( + bar, + range // + ); + + // + if (result) + { + // + Add( + resistance, + mResistanceZones // + ); + } + } + + // + return result; + } + + /** + * Detect Supply Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSupplyZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupplyAndDemandRange(); + result = range > 0; + if (!result) + { + return result; + } + + // + int hhIDX = -1; + double hh = -1; + + // + int llIDX = -1; + double ll = -1; + + // + result = mBarAnalyser + .CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + range // + ); + if (!result) + { + return result; + } + + // + XOHCL supplyBar; + result = supplyBar.Init( + bar.symbol, + bar.period, + hhIDX // + ); + if (result) + { + // + XCSupplyZone *supply; + supply = new XCSupplyZone(); + result = supply.Init( + supplyBar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + supply.To(cTime); + + // + Add( + supply, + mSupplyZones // + ); + } + } + + // + return result; + } + + /** + * Detect Demand Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectDemandZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupplyAndDemandRange(); + result = range > 0; + if (!result) + { + return result; + } + + // + int hhIDX = -1; + double hh = -1; + + // + int llIDX = -1; + double ll = -1; + + // + result = mBarAnalyser + .CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + range // + ); + if (!result) + { + return result; + } + + // + XOHCL demandBar; + result = demandBar.Init( + bar.symbol, + bar.period, + llIDX // + ); + if (result) + { + // + XCDemandZone *demand; + demand = new XCDemandZone(); + result = demand.Init( + demandBar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + demand.To(cTime); + + // + Add( + demand, + mDemandZones // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBullishOrderBlocks // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishOrderBlock( + XOHCL &bar, + XCOrderBlock *&ob // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + } + } + + // + return result; + } + + /** + * Detect Bearish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBearishOrderBlocks // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishOrderBlock( + XOHCL &bar, + XCOrderBlock *&ob // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + } + } + + // + return result; + } + + /** + * Detect Bullish Fair Value Gap ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishFairValueGap(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL prevBar; + XOHCL nextBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasFairValueGap( + bar, + prevBar, + nextBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCFVG *fvg; + fvg = new XCFVG(); + result = fvg.Init( + prevBar, + nextBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + fvg.To(cTime); + + // + Add( + fvg, + mBullishFairValueGaps // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Fair Value Gap ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishFairValueGap(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL prevBar; + XOHCL nextBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasFairValueGap( + bar, + prevBar, + nextBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCFVG *fvg; + fvg = new XCFVG(); + result = fvg.Init( + prevBar, + nextBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + fvg.To(cTime); + + // + Add( + fvg, + mBearishFairValueGaps // + ); + } + } + + // + return result; + } + + // + protected: + // + + // + // Actions ... + + /** + * Lock ... + */ + void Lock() + { + mLock = true; + } + + /** + * Unlock ... + */ + void Unlock() + { + mLock = false; + } + + /** + * Detect Required POI(s) ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + */ + void DetectRequiredPOIs(int barIndex = 0) + { + // + // Validate Reuired POI(s) ... + int requiredPOIs = MaxNumberOfRequiredPOIs(); + if (requiredPOIs <= 0) + { + return; + } + + // + // Locking Detector ... + Lock(); + + // + // Normalize Bar Index ... + if (barIndex < 0) + { + barIndex = 0; + } + + // + int swingLowsCount = 0; + int swingHighsCount = 0; + + // + int bullishMomentumBarsCount = 0; + int bearishMomentumBarsCount = 0; + + // + int bullishRejectionBarsCount = 0; + int bearishRejectionBarsCount = 0; + + // + int supportZonesCount = 0; + int resistanceZonesCount = 0; + + // + int supplyZonesCount = 0; + int demandZonesCount = 0; + + // + int bullishOrderBlocksCount = 0; + int bearishOrderBlocksCount = 0; + + // + int bullishFairValueGapsCount = 0; + int bearishFairValueGapsCount = 0; + + // + bool canContinue = true; + + // + while (canContinue) + { + // + // Swings ... + int iSwingRange = SwingRange(); + if (iSwingRange > 0) + { + // + // Swing Highs ... + swingHighsCount = DetectRequiredSwingHighs(barIndex); + if (swingHighsCount == requiredPOIs) + { + ArrayReverse(mSwingHighs); + } + + // + // Swing Lows ... + swingLowsCount = DetectRequiredSwingLows(barIndex); + if (swingLowsCount == requiredPOIs) + { + ArrayReverse(mSwingLows); + } + } + + // + bool canLookupMomentumBars = + MomentumBarExtendRange() >= 0 && + MomentumBarBodyPercent() > 0; + if (canLookupMomentumBars) + { + // + // + // Bullish Momentum Bars ... + bullishMomentumBarsCount = DetectRequiredBullishMomentumBars(barIndex); + if (bullishMomentumBarsCount == requiredPOIs) + { + ArrayReverse(mBullishMomentumBars); + } + + // + // Bearish Momentum Bars ... + bearishMomentumBarsCount = DetectRequiredBearishMomentumBars(barIndex); + if (bearishMomentumBarsCount == requiredPOIs) + { + ArrayReverse(mBearishMomentumBars); + } + } + + // + bool canLookupRejectionBars = + RejectionBarExtendRange() >= 0 && + RejectionBarShadowPercent() > 0; + if (canLookupRejectionBars) + { + // + // + // Bullish Rejection Bars ... + bullishRejectionBarsCount = DetectRequiredBullishRejectionBars(barIndex); + if (bullishRejectionBarsCount == requiredPOIs) + { + ArrayReverse(mBullishRejectionBars); + } + + // + // Bearish Rejection Bars ... + bearishRejectionBarsCount = DetectRequiredBearishRejectionBars(barIndex); + if (bearishRejectionBarsCount == requiredPOIs) + { + ArrayReverse(mBearishRejectionBars); + } + } + + // + // Support and Resistance Zones ... + int supResRange = SupportAndResistanceRange(); + if (supResRange > 0) + { + // + // Support Zone(s) ... + supportZonesCount = DetectRequiredSupportZones(barIndex); + if (supportZonesCount == requiredPOIs) + { + ArrayReverse(mSupportZones); + } + + // + // Resistance Zone(s) ... + resistanceZonesCount = DetectRequiredResistanceZones(barIndex); + if (resistanceZonesCount == requiredPOIs) + { + ArrayReverse(mResistanceZones); + } + } + + // + // Supply and Demand Zones ... + int supDemRange = SupplyAndDemandRange(); + if (supDemRange > 0) + { + // + supplyZonesCount = DetectRequiredSupplyZones(barIndex); + if (supplyZonesCount == requiredPOIs) + { + ArrayReverse(mSupplyZones); + } + + // + demandZonesCount = DetectRequiredDemandZones(barIndex); + if (demandZonesCount == requiredPOIs) + { + ArrayReverse(mDemandZones); + } + } + + // + // Oder Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Blocks ... + bullishOrderBlocksCount = DetectRequiredBullishOrderBlocks(barIndex); + if (bullishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBullishOrderBlocks); + } + + // + // Bearish Order Blocks ... + bearishOrderBlocksCount = DetectRequiredBearishOrderBlocks(barIndex); + if (bearishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBearishOrderBlocks); + } + } + + // + // Fair Value Gaps ... + int fvgSameBars = FairValueGapsSameBars(); + if (fvgSameBars > 0) + { + // + // Bullish Fair Value Gaps ... + bullishFairValueGapsCount = DetectRequiredBullishFairValueGaps(barIndex); + if (bullishFairValueGapsCount == requiredPOIs) + { + ArrayReverse(mBullishFairValueGaps); + } + + // + // Bearish Fair Value Gaps ... + bearishFairValueGapsCount = DetectRequiredBearishFairValueGaps(barIndex); + if (bearishFairValueGapsCount == requiredPOIs) + { + ArrayReverse(mBearishFairValueGaps); + } + } + + // + // Swings ... + bool canContinueSwingHighs = + iSwingRange > 0 + ? swingHighsCount < requiredPOIs + : false; + bool canContinueSwingLows = + iSwingRange > 0 + ? swingLowsCount < requiredPOIs + : false; + + // + // Support and Resistance Zones ... + bool canContinueSupportZones = + supResRange > 0 + ? supportZonesCount < requiredPOIs + : false; + bool canContinueResistanceZones = + supResRange > 0 + ? resistanceZonesCount < requiredPOIs + : false; + + // + // Supply and Demand Zones ... + bool canContinueSupplyZones = + supDemRange > 0 + ? supplyZonesCount < requiredPOIs + : false; + bool canContinueDemandZones = + supDemRange > 0 + ? demandZonesCount < requiredPOIs + : false; + + // + // Order Blocks ... + bool canContinueBullishOrderBlocks = + obSameBars > 0 + ? bullishOrderBlocksCount < requiredPOIs + : false; + bool canContinueBearishOrderBlocks = + obSameBars > 0 + ? bearishOrderBlocksCount < requiredPOIs + : false; + + // + // Fair Value Gaps ... + bool canContinueBullishFairValueGaps = + fvgSameBars > 0 + ? bullishFairValueGapsCount < requiredPOIs + : false; + bool canContinueBearishFairValueGaps = + fvgSameBars > 0 + ? bearishFairValueGapsCount < requiredPOIs + : false; + + // + // Rejection Bars ... + bool canContinueBullishRejectionBars = + canLookupRejectionBars + ? bullishRejectionBarsCount < requiredPOIs + : false; + bool canContinueBearishRejectionBars = + canLookupRejectionBars + ? bearishRejectionBarsCount < requiredPOIs + : false; + + // + // Momentum Bars ... + bool canContinueBullishMomentumBars = + canLookupMomentumBars + ? bullishMomentumBarsCount < requiredPOIs + : false; + bool canContinueBearishMomentumBars = + canLookupMomentumBars + ? bearishMomentumBarsCount < requiredPOIs + : false; + + // + canContinue = + // + // Swings ... + canContinueSwingHighs || + canContinueSwingLows || + // + // Support and Resistance Zones ... + canContinueSupportZones || + canContinueResistanceZones || + // + // Supply and Demand Zones ... + canContinueSupplyZones || + canContinueDemandZones || + // + // Order Blocks ... + canContinueBullishOrderBlocks || + canContinueBearishOrderBlocks || + // + // Fair Value Gaps ... + canContinueBullishFairValueGaps || + canContinueBearishFairValueGaps || + // + // Rejection Bars ... + canContinueBullishRejectionBars || + canContinueBearishRejectionBars || + // + // Momentum Bars ... + canContinueBullishMomentumBars || + canContinueBearishMomentumBars + // + ; + if (canContinue) + { + barIndex++; + } + } + + // + // Unlocking Detector ... + Unlock(); + } + + /** + * Validate Founded POI(s) ... + * + * @param bar: XOHCL instance ... + */ + void ValidatePOIs(XOHCL &bar) + { + } + + /** + * Cleanup Unused Objects ... + */ + void CleanupUnusedPOIs() + { + // + int maxAllowed = MaxNumberOfPOIs(); + if (!IsValidSize(maxAllowed)) + { + return; + } + + // + int swingHighsCount = ArraySize(mSwingHighs); + int swingLowsCount = ArraySize(mSwingLows); + // int tradingDaysCount = ArraySize(mTradingDays); + // int marketSessionsCount = ArraySize(mMarketSessions); + // int momentumBarsCount = ArraySize(mMomentumBars); + // int rejectionBarsCount = ArraySize(mRejectionBars); + // int supportZonesCount = ArraySize(mSupportZones); + // int resistanceZonesCount = ArraySize(mResistanceZones); + // int supplyZonesCount = ArraySize(mSupplyZones); + // int demandZonesCount = ArraySize(mDemandZones); + // int bullishOBsCount = ArraySize(mBullishOrderBlocks); + // int bearishOBsCount = ArraySize(mBearishOrderBlocks); + // int bullishFVGsCount = ArraySize(mBullishFVGs); + // int bearishFVGsCount = ArraySize(mBearishFVGs); + + // + int from = 0; + int requiredPOIs = MaxNumberOfRequiredPOIs(); + int count = maxAllowed - requiredPOIs; + int to = count - 1; + + // + // Swings ... + + // // + // // Swing Highs ... + // if (swingHighsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSwingHighs, + // from, + // count // + // ); + // } + + // // + // // Swing Lows ... + // if (swingLowsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSwingLows, + // from, + // count // + // ); + // } + + // // + // // Trading Days ... + // if (tradingDaysCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mTradingDays, + // from, + // count // + // ); + + // // + // mTradingDayObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Market Sessions ... + // if (marketSessionsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mMarketSessions, + // from, + // count // + // ); + + // // + // mMarketSessionObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Momentum Bars ... + // if (momentumBarsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mMomentumBars, + // from, + // count // + // ); + + // // + // mMomentumBarObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Rejection Bars ... + // if (rejectionBarsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mRejectionBars, + // from, + // count // + // ); + + // // + // mRejectionBarObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Support and Resistance Zones ... + + // // + // // Support Zones ... + // if (supportZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSupportZones, + // from, + // count // + // ); + + // // + // mSupportZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Resistance Zones ... + // if (resistanceZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mResistanceZones, + // from, + // count // + // ); + + // // + // mResistanceZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Supply and Demand Zones ... + + // // + // // Supply Zones ... + // if (supplyZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSupplyZones, + // from, + // count // + // ); + + // // + // mSupplyZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Demand Zones ... + // if (demandZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mDemandZones, + // from, + // count // + // ); + + // // + // mDemandZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Order Blocks ... + + // // + // // Bullish Order Blocks ... + // if (bullishOBsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBullishOrderBlocks, + // from, + // count // + // ); + + // // + // mBullishOrderBlockObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Bearish Order Blocks ... + // if (bearishOBsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBearishOrderBlocks, + // from, + // count // + // ); + + // // + // mBearishOrderBlockObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Fair Vakue Gaps ... + + // // + // // Bullish FVGs ... + // if (bullishFVGsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBullishFVGs, + // from, + // count // + // ); + + // // + // mBullishFVGObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Bearish FVGs ... + // if (bearishFVGsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBearishFVGs, + // from, + // count // + // ); + + // // + // mBearishFVGObjects.DeleteRange( + // from, + // to // + // ); + // } + + // + } + + /** + * Notify Event Listeners ... + * + * @param event: ENUM_XPOI_EVENTS member, Specified Occured Event ... + * @param param: XCBasePOI implementation, Specified Event Object ... + */ + void NotifyEventListeners( + ENUM_XPOI_EVENTS event, + XCBasePOI *param // + ) + { + // + int count = ArraySize(mEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mEventListeners[i]( + event, + param // + ); + } + } + + void AddObjectIfNotExists(XCBaseObject *object) + { + // + string name = object.ObjName(); + + // + bool canAdd = true; + int count = mDrawnObjects.Total(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + string iName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); + + // + if (name == iName) + { + // + canAdd = false; + break; + } + } + } + + // + if (canAdd) + { + mDrawnObjects.Add(object); + } + } + + // + private: + // + + // + // Props ... + + // + bool mLock; // Lock State ... + string mSymbol; // Market Symbol ... + ENUM_TIMEFRAMES mPeriod; // Market Period ... + int mMaxNumberOfPOIs; // Max Allowed Number of POI(s) which Can Holds ... + int mMaxNumberOfRequiredPOIs; // Max Allowed Number of POI(s) which Must Find at Initializion Time ... + + // + CArrayObj mDrawnObjects; // Drawn Objects ... + XBarTracker mBarTracker; // Market Bar Tracker ... + XCBarAnalyser mBarAnalyser; // Bar Analyser ... + + // + TOnPOIEvent mEventListeners[]; // Event Listeners ... + + // + // POI Props ... + + // + // XDay ... + + // + // XSession ... + + // + // XSwing ... + int mSwingRange; // Swing Verification Range Length ... + + // + // Swing High ... + + // + XCSwing *mSwingHighs[]; // Holds Founded Swing Highs ... + + /** + * Detect Required Swing Highs ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSwingHighs(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSwingHighs); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SwingRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSwingHigh(bar); + + // + result = ArraySize(mSwingHighs); + + // + return result; + } + + // + // Swing Low ... + + // + XCSwing *mSwingLows[]; // Holds Founded Swing Lows ... + + /** + * Detect Required Swing Lows ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSwingLows(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSwingLows); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SwingRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSwingLow(bar); + + // + result = ArraySize(mSwingLows); + + // + return result; + } + + // + // Momentum Bars ... + int mMomentumBarExtendRange; // Momentum Bars must Extends Range ... + double mMomentumBarBodyPercent; // Momentum Bars Body Percent ... + + // + // Bullish ... + XCMomentumBar *mBullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ... + + /** + * Detect Required Bullish Momentum Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishMomentumBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishMomentumBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishMomentumBar(bar); + + // + result = ArraySize(mBullishMomentumBars); + + // + return result; + } + + // + // Bearish ... + XCMomentumBar *mBearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ... + + /** + * Detect Required Bearish Momentum Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishMomentumBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishMomentumBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishMomentumBar(bar); + + // + result = ArraySize(mBearishMomentumBars); + + // + return result; + } + + // + // Rejection Bars ... + int mRejectionBarExtendRange; // Rejection Bars must Extends Range ... + double mRejectionBarShadowPercent; // Rejection Bars Shadow Percent ... + + // + // Bullish ... + XCRejectionBar *mBullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ... + + /** + * Detect Required Bullish Rejection Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishRejectionBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishRejectionBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishRejectionBar(bar); + + // + result = ArraySize(mBullishRejectionBars); + + // + return result; + } + + // + // Bearish ... + XCRejectionBar *mBearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ... + + /** + * Detect Required Bearish Rejection Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishRejectionBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishRejectionBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishRejectionBar(bar); + + // + result = ArraySize(mBearishRejectionBars); + + // + return result; + } + + // + // Support and Resistance Zone ... + int mSupportAndResistanceRange; // Support and Resistance Range for Verification ... + + // + // Support Zone(s) ... + XCSupportZone *mSupportZones[]; // Holds Founded Support Zones ... + + /** + * Detect Required Support Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSupportZones(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSupportZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupportAndResistanceRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSupportZone(bar); + + // + result = ArraySize(mSupportZones); + + // + return result; + } + + // + // Resistance Zone(s) ... + XCResistanceZone *mResistanceZones[]; // Holds Founded Resistance Zones ... + + /** + * Detect Required Resistance Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredResistanceZones(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mResistanceZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupportAndResistanceRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectResistanceZone(bar); + + // + result = ArraySize(mResistanceZones); + + // + return result; + } + + // + // Supply and Demand Zones ... + int mSupplyAndDemandRange; // Supply and Demand Range Verifications ... + + // + // Supply Zone(s) ... + XCSupplyZone *mSupplyZones[]; // Holds Founded Supply Zones ... + + /** + * Detect Required Supply Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSupplyZones(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSupplyZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupplyAndDemandRange(); + if (range < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSupplyZone(bar); + + // + result = ArraySize(mSupplyZones); + + // + return result; + } + + // + // Demand Zone(s) ... + XCDemandZone *mDemandZones[]; // Holds Founded Demand Zones ... + + /** + * Detect Required Demand Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredDemandZones(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mDemandZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupplyAndDemandRange(); + if (range < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectDemandZone(bar); + + // + result = ArraySize(mDemandZones); + + // + return result; + } + + // + // Order Blocks ... + int mOrderBlocksSameBars; // Order Blocks Detection Bars ... + + // + // Bullish OB ... + XCOrderBlock *mBullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ... + + /** + * Detect Required Bullish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishOrderBlock(bar); + + // + result = ArraySize(mBullishOrderBlocks); + + // + return result; + } + + // + // Bearish OB ... + XCOrderBlock *mBearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ... + + /** + * Detect Required Bearish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishOrderBlock(bar); + + // + result = ArraySize(mBearishOrderBlocks); + + // + return result; + } + + // + // Fair Value Gaps ... + int mFairValueGapsSameBars; // Fair Value Gaps Detection Same Bars ... + + // + // Bullish FVG ... + XCFVG *mBullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ... + + /** + * Detect Required Bullish Fair Value Gaps ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishFairValueGaps(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishFairValueGaps); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishFairValueGap(bar); + + // + result = ArraySize(mBullishFairValueGaps); + + // + return result; + } + + // + // Bearish FVG ... + XCFVG *mBearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ... + + /** + * Detect Required Bearish Fair Value Gaps ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishFairValueGaps(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishFairValueGaps); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishFairValueGap(bar); + + // + result = ArraySize(mBearishFairValueGaps); + + // + return result; + } + + // + // Ticks Range Zones ... + int mTicksRangeZoneLevel; // Ticks Range Levels ... + int mTicksRangeZoneRange; // Ticks Range Zone Loopback Period ... + + // + XCTicksZone *mTicksZone; // Ticks Zone ... + // XCTicksZoneObject *mTicksZoneObject; // Ticks Zone Object ... + + /** + * Detect Ticks Zone Range ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectTicksZoneRange(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int ticksLevels = TicksRangeZoneLevel(); + int ticksRange = TicksRangeZoneRange(); + result = ticksLevels > 0 && + ticksRange > 0; + if (!result) + { + return result; + } + + // + int startBarIndex = bar.Index() + ticksRange; + XOHCL startBar; + result = startBar.Init( + bar.symbol, + bar.period, + startBarIndex // + ); + if (!result) + { + return result; + } + + // + mTicksZone = new XCTicksZone(); + result = mTicksZone.Init( + startBar, + bar // + ); + if (!result) + { + // + mTicksZone = NULL; + return result; + } + + // + return result; + } + + // + // Liquidity Zones ... + + // + // Sell Side ... + + // + // Buy Side ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-saherelm.x121.xwz.mq5 b/BKPS/14031218/Documents/BKP/x-saherelm.x121.xwz.mq5 new file mode 100644 index 0000000..8828b35 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-saherelm.x121.xwz.mq5 @@ -0,0 +1,3438 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XWZ +// Description: XWZ ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XWZ Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121_XWZ" + +// +// Includes Common Library ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; + +// +input group "Calculation"; +input ENUM_APPLIED_PRICE appliedTo = PRICE_CLOSE; // Detect Price Type + +// +input group "MA Detection"; +input int maLength = 20; // MA Length +input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method + +// +input group "ATR StopLoss"; +input int atrLength = 14; // ATR Length +input double atrMultiplier = 2; // ATR Multiplier + +// +input group "ADX Detection"; +input int adxLength = 14; // ADX Length +input double adxThreshold = 25; // ADX Threshold for Strong Trends + +// +input group "Alert"; +input bool mXWZEnableAlerts = true; // Enable Alerts +input bool mXWZPushAlerts = false; // Push Alerts +input bool mXWZMailAlerts = false; // Mail Alerts +input bool mXWZTerminalAlerts = false; // Terminal Alerts + +// +// Presentation ... +input group "Presentation"; + +// +input group "Buffer Presentation"; +input bool showMA = true; // Show Moving Average +input bool showPin = true; // Show Pin Bars +input bool showSwing = true; // Show Swing Bars +input bool showTrend = true; // Show Trend +input bool showEngulf = true; // Show Engulf Bars +input bool showLongSL = true; // Show Long SL +input bool showShortSL = true; // Show Short SL +input bool showMomentum = true; // Show Momentum Bars +input bool showRejection = true; // Show Rejection Bars + +// +input group "POI Presentation"; +input bool showPOIs = false; // Show POI(s) +input bool showActivatedPOIs = true; // Show Activated POI(s) +input bool showOrderBlocks = true; // Show Order Blocks +input bool showFairValueGaps = true; // Show Fair Value Gaps +input bool showSupportZones = false; // Show Support Zones +input bool showResistanceZones = false; // Show Resistance Zones + +// +input group "Presentation Config"; +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +input int upTrendArrowCode = 236; // Up Trend Arrow Code +input int downTrendArrowCode = 238; // Down Trend Arrow Code +input int swingLowArrowCode = 108; // Swing Low Arrow Code +input int swingHighArrowCode = 108; // Swing High Arrow Code +input int bullishPinArrowCode = 246; // Bullish Pin Arrow Code +input int bearishPinArrowCode = 248; // Bearish Pin Arrow Code +input int bullishEngulfArrowCode = 200; // Bullish Engulf Arrow Code +input int bearishEngulfArrowCode = 202; // Bearish Engulf Arrow Code +input int bullishMomentumArrowCode = 233; // Bullish Momentum Arrow Code +input int bearishMomentumArrowCode = 234; // Bearish Momentum Arrow Code +input int bullishRejectionArrowCode = 241; // Bullish Rejection Arrow Code +input int bearishRejectionArrowCode = 242; // Bearish Rejection Arrow Code + +// +#property indicator_chart_window + +// +#property indicator_buffers 17 +#property indicator_plots 15 + +// +// Plot Buffers ... + +// +#define maBufferIndex 0 +double maBuffer[]; + +// +#property indicator_label1 "X121-XWZ MA" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSkyBlue +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +// +#define longSLBufferIndex 1 +double longSLBuffer[]; + +// +#property indicator_label2 "X121-XWZ Long SL" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +#define shortSLBufferIndex 2 +double shortSLBuffer[]; + +// +#property indicator_label3 "X121-XWZ Short SL" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrOrange +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +// +#define upTrendBufferIndex 3 +double upTrendBuffer[]; + +// +#property indicator_label4 "X121-XWZ Trend Up" +#property indicator_type4 DRAW_ARROW +#property indicator_color4 clrAqua +#property indicator_width4 3 + +// +#define downTrendBufferIndex 4 +double downTrendBuffer[]; + +// +#property indicator_label5 "X121-XWZ Trend Down" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrMagenta +#property indicator_width5 3 + +// +#define bullishMomentumBufferIndex 5 +double bullishMomentumBuffer[]; + +// +#property indicator_label6 "X121-XWZ Bull Momentum" +#property indicator_type6 DRAW_ARROW +#property indicator_color6 clrAqua +#property indicator_width6 3 + +// +#define bearishMomentumBufferIndex 6 +double bearishMomentumBuffer[]; + +// +#property indicator_label7 "X121-XWZ Bear Momentum" +#property indicator_type7 DRAW_ARROW +#property indicator_color7 clrMagenta +#property indicator_width7 3 + +// +#define bullishRejectionBufferIndex 7 +double bullishRejectionBuffer[]; + +// +#property indicator_label8 "X121-XWZ Bull Rejection" +#property indicator_type8 DRAW_ARROW +#property indicator_color8 clrAqua +#property indicator_width8 3 + +// +#define bearishRejectionBufferIndex 8 +double bearishRejectionBuffer[]; + +// +#property indicator_label9 "X121-XWZ Bear Rejection" +#property indicator_type9 DRAW_ARROW +#property indicator_color9 clrMagenta +#property indicator_width9 3 + +// +#define bullishPinBufferIndex 9 +double bullishPinBuffer[]; + +// +#property indicator_label10 "X121-XWZ Bull Pin" +#property indicator_type10 DRAW_ARROW +#property indicator_color10 clrAqua +#property indicator_width10 3 + +// +#define bearishPinBufferIndex 10 +double bearishPinBuffer[]; + +// +#property indicator_label11 "X121-XWZ Bear Pin" +#property indicator_type11 DRAW_ARROW +#property indicator_color11 clrMagenta +#property indicator_width11 3 + +// +#define bullishEngulfBufferIndex 11 +double bullishEngulfBuffer[]; + +// +#property indicator_label12 "X121-XWZ Bull Engulf" +#property indicator_type12 DRAW_ARROW +#property indicator_color12 clrAqua +#property indicator_width12 3 + +// +#define bearishEngulfBufferIndex 12 +double bearishEngulfBuffer[]; + +// +#property indicator_label13 "X121-XWZ Bear Engulf" +#property indicator_type13 DRAW_ARROW +#property indicator_color13 clrMagenta +#property indicator_width13 3 + +// +#define swingLowBufferIndex 13 +double swingLowBuffer[]; + +// +#property indicator_label14 "X121-XWZ Swing Low" +#property indicator_type14 DRAW_ARROW +#property indicator_color14 clrAqua +#property indicator_width14 3 + +// +#define swingHighBufferIndex 14 +double swingHighBuffer[]; + +// +#property indicator_label15 "X121-XWZ Swing High" +#property indicator_type15 DRAW_ARROW +#property indicator_color15 clrMagenta +#property indicator_width15 3 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 14; + +// +#define atrBufferIndex mLastBufferIndex + 1 +double atrBuffer[]; + +// +#define adxBufferIndex mLastBufferIndex + 2 +double adxBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// MA Handler ... +int maHandler = INVALID_HANDLE; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +// ADX Handler ... +int adxHandler = INVALID_HANDLE; + +// +XCAlert *mXWZAlert; +CArrayObj mXWZDrawnObjects; +XCPOIDrawer *mXWZPOIDrawer; +XCBarAnalyser *mXWZBarAnalyser; + +// +datetime lastBullishTrend = NULL; +datetime lastBearishTrend = NULL; + +// +datetime lastCrossedOverMA = NULL; +datetime lastCrossedUnderMA = NULL; + +// +// POI(s) ... + +// +bool mXWZDetectOrderBlocks = true; +bool mXWZDetectFairValueGaps = false; +bool mXWZDetectSupportZones = false; +bool mXWZDetectResistanceZones = false; + +// +bool filterPOIsUsingMa = false; // Filter POI(s) Using MA +bool filterPOIsUsingZones = false; // Filter POI(s) Using Zones + +// +XCFVG *lastBullFVG; +XCFVG *lastBearFVG; +XCOrderBlock *lastBullOB; +XCOrderBlock *lastBearOB; +XCSupportZone *lastSupport; +XCResistanceZone *lastResistance; + +// +// Un Activated POI(s) ... +XCFVG *mXWZUnActivatedFVGs[]; +XCOrderBlock *mXWZUnActivatedOBs[]; +XCSupportZone *mXWZUnActivatedSupportZones[]; +XCResistanceZone *mXWZUnActivatedResistanceZones[]; + +// +// Activated POI(s) ... +XCFVG *mXWZActivatedFVGs[]; +XCOrderBlock *mXWZActivatedOBs[]; +XCSupportZone *mXWZActivatedSupportZones[]; +XCResistanceZone *mXWZActivatedResistanceZones[]; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + mXWZDrawnObjects.Clear(); + + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // MA ... + maHandler = iMA( + _Symbol, + _Period, + maLength, + 0, + maMethod, + appliedTo // + ); + bool isInited = maHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength // + ); + isInited = maHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ADX ... + adxHandler = iADX( + _Symbol, + _Period, + adxLength // + ); + isInited = maHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + // + mXWZPOIDrawer = new XCPOIDrawer(); + ConfigurePOIDrawer(); + + // + mXWZAlert = new XCAlert(); + ConfigureAlert(); + + // + mXWZBarAnalyser = new XCBarAnalyser(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(maHandler); + IndicatorRelease(atrHandler); + IndicatorRelease(adxHandler); + + // + mXWZDrawnObjects.Clear(); + + // + ZeroMemory(mXWZAlert); + ZeroMemory(mXWZPOIDrawer); + ZeroMemory(mXWZBarAnalyser); + + // + Clean(mXWZActivatedOBs); + Clean(mXWZActivatedFVGs); + Clean(mXWZActivatedSupportZones); + Clean(mXWZActivatedResistanceZones); + + // + Clean(mXWZUnActivatedOBs); + Clean(mXWZUnActivatedFVGs); + Clean(mXWZUnActivatedSupportZones); + Clean(mXWZUnActivatedResistanceZones); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + // MA ... + int maCalculatedBars = BarsCalculated(maHandler); + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + // ADX ... + int adxCalculatedBars = BarsCalculated(adxHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // MA ... + maCalculatedBars >= maxLength && + // + // ATR ... + atrCalculatedBars >= maxLength && + // + // ADX ... + adxCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // MA ... + int copiedMas = CopyBuffer(maHandler, 0, 0, limit, maBuffer); + + // + // ATR ... + int copiedAtr = CopyBuffer(atrHandler, MAIN_LINE, 0, limit, atrBuffer); + + // + // ADX ... + int copiedAdxs = CopyBuffer(adxHandler, MAIN_LINE, 0, limit, adxBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // MA ... + copiedMas > 0 && + // + // ATR ... + copiedAtr > 0 && + // + // ADX ... + copiedAdxs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + // + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // MA ... + maLength > 0 && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // ADX ... + adxLength > 0 && + adxThreshold > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(maLength, atrLength); + result = MathMax(result, adxLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // MA Buffer ... + + // + ENUM_DRAW_TYPE maDrawType = showMA ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(maBuffer, true); + SetIndexBuffer(maBufferIndex, maBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maBufferIndex, PLOT_SHOW_DATA, showMA); + PlotIndexSetInteger(maBufferIndex, PLOT_DRAW_TYPE, maDrawType); + + // + PlotIndexSetDouble(maBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // LONG SL Buffer ... + + // + ENUM_DRAW_TYPE longSLDrawType = showLongSL ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(longSLBuffer, true); + SetIndexBuffer(longSLBufferIndex, longSLBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(longSLBufferIndex, PLOT_SHOW_DATA, showLongSL); + PlotIndexSetInteger(longSLBufferIndex, PLOT_DRAW_TYPE, longSLDrawType); + + // + PlotIndexSetDouble(longSLBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // SHORT SL Buffer ... + + // + ENUM_DRAW_TYPE shortSLDrawType = showShortSL ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(shortSLBuffer, true); + SetIndexBuffer(shortSLBufferIndex, shortSLBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(shortSLBufferIndex, PLOT_SHOW_DATA, showShortSL); + PlotIndexSetInteger(shortSLBufferIndex, PLOT_DRAW_TYPE, shortSLDrawType); + + // + PlotIndexSetDouble(shortSLBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // UP Trend ... + + // + ENUM_DRAW_TYPE upTrendDrawType = showTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(upTrendBuffer, true); + SetIndexBuffer(upTrendBufferIndex, upTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(upTrendBufferIndex, PLOT_SHOW_DATA, showTrend); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_DRAW_TYPE, upTrendDrawType); + + // + PlotIndexSetDouble(upTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_ARROW, upTrendArrowCode); + + // + // DOWN Trend ... + + // + ENUM_DRAW_TYPE downTrendDrawType = showTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(downTrendBuffer, true); + SetIndexBuffer(downTrendBufferIndex, downTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(downTrendBufferIndex, PLOT_SHOW_DATA, showTrend); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_DRAW_TYPE, downTrendDrawType); + + // + PlotIndexSetDouble(downTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_ARROW, downTrendArrowCode); + + // + // Bullish Momentum ... + + // + ENUM_DRAW_TYPE bullishMomentumDrawType = showMomentum ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishMomentumBuffer, true); + SetIndexBuffer(bullishMomentumBufferIndex, bullishMomentumBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_SHOW_DATA, showMomentum); + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_DRAW_TYPE, bullishMomentumDrawType); + + // + PlotIndexSetDouble(bullishMomentumBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_ARROW, bullishMomentumArrowCode); + + // + // Bearish Momentum ... + + // + ENUM_DRAW_TYPE bearishMomentumDrawType = showMomentum ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishMomentumBuffer, true); + SetIndexBuffer(bearishMomentumBufferIndex, bearishMomentumBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_SHOW_DATA, showMomentum); + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_DRAW_TYPE, bearishMomentumDrawType); + + // + PlotIndexSetDouble(bearishMomentumBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_ARROW, bearishMomentumArrowCode); + + // + // Bullish Rejection ... + + // + ENUM_DRAW_TYPE bullishRejectionDrawType = showRejection ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishRejectionBuffer, true); + SetIndexBuffer(bullishRejectionBufferIndex, bullishRejectionBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_SHOW_DATA, showRejection); + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_DRAW_TYPE, bullishRejectionDrawType); + + // + PlotIndexSetDouble(bullishRejectionBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_ARROW, bullishRejectionArrowCode); + + // + // Bearish Rejection ... + + // + ENUM_DRAW_TYPE bearishRejectionDrawType = showRejection ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishRejectionBuffer, true); + SetIndexBuffer(bearishRejectionBufferIndex, bearishRejectionBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_SHOW_DATA, showRejection); + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_DRAW_TYPE, bearishRejectionDrawType); + + // + PlotIndexSetDouble(bearishRejectionBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_ARROW, bearishRejectionArrowCode); + + // + // Bullish Pin ... + + // + ENUM_DRAW_TYPE bullishPinDrawType = showPin ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishPinBuffer, true); + SetIndexBuffer(bullishPinBufferIndex, bullishPinBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_SHOW_DATA, showPin); + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_DRAW_TYPE, bullishPinDrawType); + + // + PlotIndexSetDouble(bullishPinBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_ARROW, bullishPinArrowCode); + + // + // Bearish Pin ... + + // + ENUM_DRAW_TYPE bearishPinDrawType = showPin ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishPinBuffer, true); + SetIndexBuffer(bearishPinBufferIndex, bearishPinBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_SHOW_DATA, showPin); + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_DRAW_TYPE, bearishPinDrawType); + + // + PlotIndexSetDouble(bearishPinBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_ARROW, bearishPinArrowCode); + + // + // Bullish Engulf ... + + // + ENUM_DRAW_TYPE bullishEngulfDrawType = showEngulf ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishEngulfBuffer, true); + SetIndexBuffer(bullishEngulfBufferIndex, bullishEngulfBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_SHOW_DATA, showEngulf); + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_DRAW_TYPE, bullishEngulfDrawType); + + // + PlotIndexSetDouble(bullishEngulfBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_ARROW, bullishEngulfArrowCode); + + // + // Bearish Engulf ... + + // + ENUM_DRAW_TYPE bearishEngulfDrawType = showEngulf ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishEngulfBuffer, true); + SetIndexBuffer(bearishEngulfBufferIndex, bearishEngulfBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_SHOW_DATA, showEngulf); + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_DRAW_TYPE, bearishEngulfDrawType); + + // + PlotIndexSetDouble(bearishEngulfBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_ARROW, bearishEngulfArrowCode); + + // + // Swing Low ... + + // + ENUM_DRAW_TYPE swingLowDrawType = showSwing ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingLowBuffer, true); + SetIndexBuffer(swingLowBufferIndex, swingLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingLowBufferIndex, PLOT_SHOW_DATA, showSwing); + PlotIndexSetInteger(swingLowBufferIndex, PLOT_DRAW_TYPE, swingLowDrawType); + + // + PlotIndexSetDouble(swingLowBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingLowBufferIndex, PLOT_ARROW, swingLowArrowCode); + + // + // Swing High ... + + // + ENUM_DRAW_TYPE swingHighDrawType = showSwing ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingHighBuffer, true); + SetIndexBuffer(swingHighBufferIndex, swingHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingHighBufferIndex, PLOT_SHOW_DATA, showSwing); + PlotIndexSetInteger(swingHighBufferIndex, PLOT_DRAW_TYPE, swingHighDrawType); + + // + PlotIndexSetDouble(swingHighBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingHighBufferIndex, PLOT_ARROW, swingHighArrowCode); + + // + // DATA Buffers ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxBuffer, true); + SetIndexBuffer(adxBufferIndex, adxBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculatedPOIs( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateValues( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + maBuffer[barIndex] = 0; + atrBuffer[barIndex] = 0; + adxBuffer[barIndex] = 0; + longSLBuffer[barIndex] = 0; + shortSLBuffer[barIndex] = 0; + upTrendBuffer[barIndex] = 0; + swingLowBuffer[barIndex] = 0; + swingHighBuffer[barIndex] = 0; + downTrendBuffer[barIndex] = 0; + bullishPinBuffer[barIndex] = 0; + bearishPinBuffer[barIndex] = 0; + bullishEngulfBuffer[barIndex] = 0; + bearishEngulfBuffer[barIndex] = 0; + bullishMomentumBuffer[barIndex] = 0; + bearishMomentumBuffer[barIndex] = 0; + bullishRejectionBuffer[barIndex] = 0; + bearishRejectionBuffer[barIndex] = 0; +} + +/** + * Calculate Vales ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateValues( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Prepare Requirements ... + + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!isInited) + { + // + iBar.Clean(); + return; + } + + // + XOHCL pBar; + isInited = iBar.GetPreviousBar(pBar); + if (!isInited) + { + // + iBar.Clean(); + pBar.Clean(); + return; + } + int pIndex = pBar.Index(); + + // + // Calculate Applied Price ... + double iPrice = GetAppliedPrice( + appliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + double iMa = maBuffer[bar_index]; + double iMaPrev = maBuffer[pIndex]; + double iAtr = atrBuffer[bar_index]; + double iAdx = adxBuffer[bar_index]; + double iAppliedAtr = iAtr * atrMultiplier; + + // + double points = GetPoints(_Symbol); + double points10 = 10 * points; + + // + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + bool hasLastBullOB = lastBullOB != NULL && + lastBullOB.IsValid(); + bool hasLastBearOB = lastBearOB != NULL && + lastBearOB.IsValid(); + + // + bool hasLastBullFVG = lastBullFVG != NULL && + lastBullFVG.IsValid(); + bool hasLastBearFVG = lastBearFVG != NULL && + lastBearFVG.IsValid(); + + // + bool hasLastSupport = lastSupport != NULL && + lastSupport.IsValid(); + + // + bool hasLastResistance = lastResistance != NULL && + lastResistance.IsValid(); + + // + // Calculate Crossing Over / Under Ma ... + bool isCrossedOverMA = + // + iBar.low > iMa && + (pBar.low <= iMaPrev && + (pBar.GetUp() <= iMaPrev || + pBar.GetDown() <= iMaPrev)) + // + ; + bool isCrossedUnderMA = + // + iBar.high < iMa && + (pBar.high >= iMaPrev && + (pBar.GetUp() >= iMaPrev || + pBar.GetDown() >= iMaPrev)) + // + ; + lastCrossedOverMA = + isCrossedOverMA + ? iBar.time + : lastCrossedOverMA; + lastCrossedUnderMA = + isCrossedUnderMA + ? iBar.time + : lastCrossedUnderMA; + + // + // SL Buffers ... + + // + double iLongSL = iPrice - iAppliedAtr; + double iShortSL = iPrice + iAppliedAtr; + + // + longSLBuffer[bar_index] = iLongSL; + shortSLBuffer[bar_index] = iShortSL; + + // + // Trend Buffers ... + + // + bool isUpTrend = + // + iPrice > iMa && + iBar.low < iMa && + iAdx > adxThreshold + // + ; + + // + bool isDownTrend = + // + iPrice < iMa && + iBar.high > iMa && + iAdx > adxThreshold + // + ; + + // + double upTrendValue = 0; + double downTrendValue = 0; + if (isUpTrend) + { + // + lastBullishTrend = iBar.time; + upTrendValue = iBar.low; + } + if (isDownTrend) + { + // + lastBearishTrend = iBar.time; + downTrendValue = iBar.high; + } + + // + upTrendBuffer[bar_index] = upTrendValue; + downTrendBuffer[bar_index] = downTrendValue; + + // + // Momentum Buffers ... + + // + bool isMomentum = mXWZBarAnalyser + .IsMomentumBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishMomentum = + isMomentum && + IsBullish(iDir); + bool isBearishMomentum = + isMomentum && + IsBearish(iDir); + if (isMomentum) + { + // + double iBullMomentumValue = 0; + double iBearMomentumValue = 0; + + // + if (isBullishMomentum) + { + // + double selectedValue = iBar.low; + + // + iBullMomentumValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBullOB + ? 0 + : IsInside( + selectedValue, + lastBullOB // + ) + ? selectedValue + : 0; + + // + iBullMomentumValue = + !filterPOIsUsingMa + ? iBullMomentumValue + : iBullMomentumValue < iMa + ? iBullMomentumValue + : 0; + } + + // + if (isBearishMomentum) + { + // + double selectedValue = iBar.high; + + // + iBearMomentumValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBearOB + ? 0 + : IsInside( + selectedValue, + lastBearOB // + ) + ? selectedValue + : 0; + + // + iBearMomentumValue = + !filterPOIsUsingMa + ? iBearMomentumValue + : iBearMomentumValue > iMa + ? iBearMomentumValue + : 0; + } + + // + bullishMomentumBuffer[bar_index] = iBullMomentumValue; + bearishMomentumBuffer[bar_index] = iBearMomentumValue; + } + + // + // Rejection Buffers ... + + // + bool isRejection = mXWZBarAnalyser + .IsRejectionBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishRejection = + isRejection && + IsBullish(iDir); + bool isBearishRejection = + isRejection && + IsBearish(iDir); + if (isRejection) + { + // + double iBullRejectionValue = 0; + double iBearRejectionValue = 0; + + // + if (isBullishRejection) + { + // + double selectedValue = iBar.low; + + // + iBullRejectionValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBullOB + ? 0 + : IsInside( + selectedValue, + lastBullOB // + ) + ? selectedValue + : 0; + + // + iBullRejectionValue = + !filterPOIsUsingMa + ? iBullRejectionValue + : iBullRejectionValue < iMa + ? iBullRejectionValue + : 0; + } + + // + if (isBearishRejection) + { + // + double selectedValue = iBar.high; + + // + iBearRejectionValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBearOB + ? 0 + : IsInside( + selectedValue, + lastBearOB // + ) + ? selectedValue + : 0; + + // + iBearRejectionValue = + !filterPOIsUsingMa + ? iBearRejectionValue + : iBearRejectionValue > iMa + ? iBearRejectionValue + : 0; + } + + // + bullishRejectionBuffer[bar_index] = iBullRejectionValue; + bearishRejectionBuffer[bar_index] = iBearRejectionValue; + } + + // + // Pin Buffers ... + + // + bool isPin = mXWZBarAnalyser + .IsPinBar( + iBar, + iDir, + 0, // Extends ... + 50, // Shadow Percent ... + 25 // Body Percent ... + ); + bool isBullishPin = + isPin && + IsBullish(iDir); + bool isBearishPin = + isPin && + IsBearish(iDir); + if (isPin) + { + // + double iBullPinValue = 0; + double iBearPinValue = 0; + + // + if (isBullishPin) + { + // + double selectedValue = iBar.low; + + // + iBullPinValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBullOB + ? 0 + : IsInside( + selectedValue, + lastBullOB // + ) + ? selectedValue + : 0; + + // + iBullPinValue = + !filterPOIsUsingMa + ? iBullPinValue + : iBullPinValue < iMa + ? iBullPinValue + : 0; + } + + // + if (isBearishPin) + { + // + double selectedValue = iBar.high; + + // + iBearPinValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBearOB + ? 0 + : IsInside( + selectedValue, + lastBearOB // + ) + ? selectedValue + : 0; + + // + iBearPinValue = + !filterPOIsUsingMa + ? iBearPinValue + : iBearPinValue > iMa + ? iBearPinValue + : 0; + } + + // + bullishPinBuffer[bar_index] = iBullPinValue; + bearishPinBuffer[bar_index] = iBearPinValue; + } + + // + // Engulf Buffers ... + + // + bool isEngulf = mXWZBarAnalyser + .IsEngulfBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishEngulf = + isEngulf && + IsBullish(iDir); + bool isBearishEngulf = + isEngulf && + IsBearish(iDir); + if (isEngulf) + { + // + double iBullEngulfValue = 0; + double iBearEngulfValue = 0; + + // + if (isBullishEngulf) + { + // + double selectedValue = iBar.low; + + // + iBullEngulfValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBullOB + ? 0 + : IsInside( + selectedValue, + lastBullOB // + ) + ? selectedValue + : 0; + + // + iBullEngulfValue = + !filterPOIsUsingMa + ? iBullEngulfValue + : iBullEngulfValue < iMa + ? iBullEngulfValue + : 0; + } + + // + if (isBearishEngulf) + { + // + double selectedValue = iBar.high; + + // + iBearEngulfValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBearOB + ? 0 + : IsInside( + selectedValue, + lastBearOB // + ) + ? selectedValue + : 0; + + // + iBearEngulfValue = + !filterPOIsUsingMa + ? iBearEngulfValue + : iBearEngulfValue > iMa + ? iBearEngulfValue + : 0; + } + + // + bullishEngulfBuffer[bar_index] = iBullEngulfValue; + bearishEngulfBuffer[bar_index] = iBearEngulfValue; + } + + // + // Swing Buffers ... + + // + bool isSwing = mXWZBarAnalyser + .IsSwing( + iBar, + iDir, + 2 // Range ... + ); + bool isSwingLow = + isSwing && + IsBullish(iDir); + bool isSwingHigh = + isSwing && + IsBearish(iDir); + if (isSwing) + { + // + double iSwingLowValue = 0; + double iSwingHighValue = 0; + + // + if (isSwingLow) + { + // + double selectedValue = iBar.low; + + // + iSwingLowValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBullOB + ? 0 + : IsBelow( + selectedValue, + lastBullOB // + ) + ? selectedValue + : 0; + + // + iSwingLowValue = + !filterPOIsUsingMa + ? iSwingLowValue + : iSwingLowValue < iMa + ? iSwingLowValue + : 0; + } + + // + if (isSwingHigh) + { + // + double selectedValue = iBar.high; + + // + iSwingHighValue = + !filterPOIsUsingZones + ? selectedValue + : !hasLastBearOB + ? 0 + : IsAbove( + selectedValue, + lastBearOB // + ) + ? selectedValue + : 0; + + // + iSwingHighValue = + !filterPOIsUsingMa + ? iSwingHighValue + : iSwingHighValue > iMa + ? iSwingHighValue + : 0; + } + + // + swingLowBuffer[bar_index] = iSwingLowValue; + swingHighBuffer[bar_index] = iSwingHighValue; + } + + // + // + // + + // + DetectSignals( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Cleanup Resources ... + + // + iBar.Clean(); + pBar.Clean(); +} + +// +void ConfigureAlert() +{ + // + mXWZAlert.SetPrefix(ShortName); + + // + mXWZAlert.SetPushAlerts(mXWZPushAlerts); + mXWZAlert.SetMailAlerts(mXWZMailAlerts); + mXWZAlert.SetEnableAlerts(mXWZEnableAlerts); + mXWZAlert.SetTerminalAlerts(mXWZTerminalAlerts); +} + +// +void DetectSignals( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Calculate Signals ... + + // + XOHCL bar; + XOHCL pBar; + XOHCL ppBar; + bool isInited = bar.Init( + _Symbol, + _Period, + barIndex // + ); + if (!isInited) + { + return; + } + + // + isInited = bar.GetPreviousBar(pBar); + if (!isInited) + { + return; + } + + // + isInited = pBar.GetPreviousBar(ppBar); + if (!isInited) + { + return; + } + + // + int pIDX = pBar.Index(); + int ppIDX = ppBar.Index(); + + // + // Reading Buffers ... + + // + double ma = maBuffer[barIndex]; + double maPrev = maBuffer[pIDX]; + double maPPrev = maBuffer[ppIDX]; + + // + // Pin Bar ... + bool isBullisPinned = bullishPinBuffer[pIDX] > 0; + bool isBearisPinned = bearishPinBuffer[pIDX] > 0; + + // + // Engulf Bar ... + bool isBullisEngulfed = bullishEngulfBuffer[pIDX] > 0; + bool isBearisEngulfed = bearishEngulfBuffer[pIDX] > 0; + + // + // Rejection Bar ... + bool isBullishRejected = bullishRejectionBuffer[pIDX] > 0; + bool isBearishRejected = bearishRejectionBuffer[pIDX] > 0; + + // + // Momentum Bar ... + bool isBullishMomentum = bullishMomentumBuffer[pIDX] > 0; + bool isBearishMomentum = bearishMomentumBuffer[pIDX] > 0; + + // + // Checking Pullback ... + ENUM_X_DIRECTION pullbackDir; + bool hasPullback = mXWZBarAnalyser.HasPullBack( + pullbackDir, + bar // + ); + bool hasBullishPullback = + hasPullback && + IsBullish(pullbackDir); + bool hasBearishPullback = + hasPullback && + IsBearish(pullbackDir); + + // + // Order Block Parsing ... + + // // + // bool isMACrossedOverBullishOB = + // // + // lastBullOB != NULL && + // lastBullOB.IsValid() && + // // + // IsInside( + // maPPrev, + // lastBullOB // + // ) && + // // + // IsAbove( + // maPrev, + // lastBullOB // + // ) + // // + // ; + + // // + // bool isMACrossedUnderBearishOB = + // // + // lastBearOB != NULL && + // lastBearOB.IsValid() && + // // + // IsInside( + // maPPrev, + // lastBearOB // + // ) && + // // + // IsBelow( + // maPrev, + // lastBearOB // + // ) + // // + // ; + + // + // Bullish ... + // -------------- + // -[] a Bullish Wave Which Crossed Over MA ... + // -[] Trend is Bullish ... + // -[] PullBack to MA ... + // -[] Has a Bllish Rejection ... + bool hasBullishSignal = + // + pBar.IsBullish() && + pBar.low < maPrev && + pBar.GetDown() >= maPrev && + // + bar.open >= ma && + // + hasBearishPullback && + // + false + // + ; + + // + // Bearish ... + // -------------- + // -[] a Bearish Wave Which Crossed Under MA ... + // -[] Trend is Bearish ... + // -[] PullBack to MA ... + // -[] Has a Bearish Rejection ... + bool hasBearishSignal = + // + false + // pBar.IsBearish() && + // pBar.high > maPrev && + // pBar.GetUp() <= maPrev && + // // + // bar.open <= ma && + // // + // true + // + ; + + // + // Draw ... + // + + // + long chartID = mXWZPOIDrawer.ChartIdentification(); + int window = mXWZPOIDrawer.SubWindowIdentification(); + + // // + // if (isMACrossedOverBullishOB) + // { + // // + // string name = + // "Bullish_" + + // ToMD5(ToFormatString(pBar.time)); + + // // + // CChartObjectVLine *iLine; + // iLine = new CChartObjectVLine(); + // bool isCreated = iLine.Create( + // chartID, + // name, + // window, + // pBar.time // + // ); + // if (isCreated) + // { + // // + // iLine.Color(clrAqua); + + // // + // mXWZDrawnObjects.Add(iLine); + // } + // } + + // // + // if (isMACrossedUnderBearishOB) + // { + // // + // string name = + // "Bearish_" + + // ToMD5(ToFormatString(pBar.time)); + + // // + // CChartObjectVLine *iLine; + // iLine = new CChartObjectVLine(); + // bool isCreated = iLine.Create( + // chartID, + // name, + // window, + // pBar.time // + // ); + // if (isCreated) + // { + // // + // iLine.Color(clrMagenta); + + // // + // mXWZDrawnObjects.Add(iLine); + // } + // } + + // + bool hasSignal = + (hasBullishSignal || + hasBearishSignal); + if (hasSignal) + { + // + long chartID = mXWZPOIDrawer.ChartIdentification(); + int window = mXWZPOIDrawer.SubWindowIdentification(); + string name = + (hasBullishSignal + ? "Bullish_" + : "Bearish_") + + "Signal_" + ToMD5(ToFormatString(bar.time)); + color signalColor = + hasBullishSignal + ? clrYellow + : clrOrange; + + // + CChartObjectVLine *iSignal; + iSignal = new CChartObjectVLine(); + bool isCreated = iSignal.Create( + chartID, + name, + window, + bar.time // + ); + if (isCreated) + { + // + iSignal.Color(signalColor); + + // + mXWZDrawnObjects.Add(iSignal); + } + + // + bool drawRR = false; + if (drawRR) + { + // + XRR iSigRR; + ENUM_X_POSITION_TYPES type = + hasBullishSignal + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + double sl = hasBullishSignal + ? longSLBuffer[barIndex] + : shortSLBuffer[barIndex]; + + // + isCreated = iSigRR.Init( + _Symbol, + _Period, + sl, + bar.open, + type, + ShortName // + ); + if (!isCreated) + { + return; + } + + // + iSigRR.time = pBar.NextAt(); + + // + XCRRObject *iObj; + isCreated = mXWZPOIDrawer.CreateRR( + iSigRR, + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + + // + iSigRR.Clean(); + } + } + + // + bar.Clean(); + pBar.Clean(); +} + +// +// POIS Functions ... + +// +void ConfigurePOIDrawer() +{ + // + if (mXWZPOIDrawer == NULL) + { + return; + } + + // + mXWZPOIDrawer.Prefix(ShortName); + mXWZPOIDrawer.ChartIdentification(ChartID()); + mXWZPOIDrawer.SubWindowIdentification(0); + + // + mXWZPOIDrawer.BullishFVGWidth(1); + mXWZPOIDrawer.BullishFVGStyle(STYLE_DOT); + mXWZPOIDrawer.BullishFVGColor(clrAqua); + + // + mXWZPOIDrawer.BearishFVGWidth(1); + mXWZPOIDrawer.BearishFVGStyle(STYLE_DOT); + mXWZPOIDrawer.BearishFVGColor(clrMagenta); + + // + mXWZPOIDrawer.SupportZoneWidth(1); + mXWZPOIDrawer.SupportZoneStyle(STYLE_DASHDOTDOT); + mXWZPOIDrawer.SupportZoneColor(clrLime); + + // + mXWZPOIDrawer.ResistanceZoneWidth(1); + mXWZPOIDrawer.ResistanceZoneStyle(STYLE_DASHDOTDOT); + mXWZPOIDrawer.ResistanceZoneColor(clrRed); + + // + mXWZPOIDrawer.BullishOrderBlockWidth(4); + mXWZPOIDrawer.BullishOrderBlockStyle(STYLE_DASH); + mXWZPOIDrawer.BullishOrderBlockColor(clrAqua); + + // + mXWZPOIDrawer.BearishOrderBlockWidth(4); + mXWZPOIDrawer.BearishOrderBlockStyle(STYLE_DASH); + mXWZPOIDrawer.BearishOrderBlockColor(clrMagenta); +} + +// +void CalculatedPOIs( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!isInited) + { + // + iBar.Clean(); + return; + } + + // + XOHCL pBar; + isInited = iBar.GetPreviousBar(pBar); + if (!isInited) + { + // + iBar.Clean(); + pBar.Clean(); + return; + } + + // + // POI ... + DetectPOIs(iBar); + UpdatePOIs(iBar); + DrawPOIs(); + + // + iBar.Clean(); + pBar.Clean(); +} + +// +bool CanDetectPOIs() +{ + // + bool result = false; + + // + result = + // + mXWZDetectOrderBlocks || + mXWZDetectFairValueGaps || + mXWZDetectSupportZones || + mXWZDetectResistanceZones + // + ; + + // + return result; +} + +// +void DetectPOIs( + XOHCL &bar // +) +{ + // + if (!CanDetectPOIs()) + { + return; + } + + // + int idx = -1; + int range = 21; + + // + // Detect Order Block ... + + // + if (mXWZDetectOrderBlocks) + { + // + XOHCL obBar; + XCOrderBlock *ob; + ENUM_X_DIRECTION obDir; + bool hasOB = mXWZBarAnalyser.HasOrderBlock( + bar, + obBar, + obDir // + ); + bool hasBullishOB = + hasOB && + IsBullish(obDir); + bool hasBearishOB = + hasOB && + IsBearish(obDir); + if (hasOB) + { + // + ob = new XCOrderBlock(); + bool isInited = ob.Init(obBar, obDir); + if (isInited) + { + // + ENUM_X_DIRECTION iForDir = ob.GetDirection(); + bool isBullish = IsBullish(iForDir); + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = ob.IsActivated( + iForDir, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + idx = FindIndex( + ob, + mXWZUnActivatedOBs // + ); + if (!IsValidIndex(idx)) + { + // + if (isBullish) + { + lastBullOB = ob; + } + else + { + lastBearOB = ob; + } + + // + Add( + ob, + mXWZUnActivatedOBs // + ); + } + } + else + { + // + idx = FindIndex( + ob, + mXWZActivatedOBs // + ); + if (!IsValidIndex(idx)) + { + // + ob.To(activationBar.time); + + // + Add( + ob, + mXWZActivatedOBs // + ); + } + } + + // + activationBar.Clean(); + } + } + + // + obBar.Clean(); + } + + // + // Detect Fair Value Gap ... + + // + if (mXWZDetectFairValueGaps) + { + // + XOHCL fvgStartBar; + XOHCL fvgEndBar; + XCFVG *fvg; + ENUM_X_DIRECTION fvgDir; + bool hasFVG = mXWZBarAnalyser.HasFairValueGap( + bar, + fvgStartBar, + fvgEndBar, + fvgDir // + ); + bool hasBullishFVG = + hasFVG && + IsBullish(fvgDir); + bool hasBearishFVG = + hasFVG && + IsBearish(fvgDir); + if (hasFVG) + { + // + fvg = new XCFVG(); + bool isInited = fvg.Init( + fvgStartBar, + fvgEndBar, + fvgDir // + ); + if (isInited) + { + // + ENUM_X_DIRECTION iForDir = fvg.GetDirection(); + bool isBullish = IsBullish(iForDir); + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = fvg.IsActivated( + iForDir, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + idx = FindIndex( + fvg, + mXWZUnActivatedFVGs // + ); + if (!IsValidIndex(idx)) + { + // + if (isBullish) + { + lastBullFVG = fvg; + } + else + { + lastBearFVG = fvg; + } + + // + Add( + fvg, + mXWZUnActivatedFVGs // + ); + } + } + else + { + // + idx = FindIndex( + fvg, + mXWZActivatedFVGs // + ); + if (!IsValidIndex(idx)) + { + // + fvg.To(activationBar.time); + + // + Add( + fvg, + mXWZActivatedFVGs // + ); + } + } + + // + activationBar.Clean(); + } + } + + // + fvgEndBar.Clean(); + fvgStartBar.Clean(); + } + + // + // Detect Support Zone ... + + // + if (mXWZDetectSupportZones) + { + // + XOHCL supportBar; + XCSupportZone *supportZone; + bool hasSupport = mXWZBarAnalyser + .HasSupport( + bar, + supportBar, + range // + ); + if (hasSupport) + { + // + supportZone = new XCSupportZone(); + hasSupport = supportZone.Init( + supportBar, + range, + true // Use Range As Start ... + ); + + // + if (hasSupport) + { + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = supportZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + idx = FindIndex( + supportZone, + mXWZUnActivatedSupportZones // + ); + hasSupport = !IsValidIndex(idx); + if (hasSupport) + { + // + lastSupport = supportZone; + + // + Add( + supportZone, + mXWZUnActivatedSupportZones // + ); + } + } + else + { + // + idx = FindIndex( + supportZone, + mXWZActivatedSupportZones // + ); + hasSupport = !IsValidIndex(idx); + if (hasSupport) + { + // + supportZone.To(activationBar.time); + + // + Add( + supportZone, + mXWZActivatedSupportZones // + ); + } + } + + // + activationBar.Clean(); + } + } + + // + supportBar.Clean(); + } + + // + // Detect Resistance Zone ... + + // + if (mXWZDetectResistanceZones) + { + // + XOHCL resistaneBar; + XCResistanceZone *resistanceZone; + bool hasResistance = mXWZBarAnalyser + .HasResistance( + bar, + resistaneBar, + range // + ); + if (hasResistance) + { + // + resistanceZone = new XCResistanceZone(); + hasResistance = resistanceZone.Init( + resistaneBar, + range, + true // Use Range As Start ... + ); + + // + if (hasResistance) + { + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = resistanceZone.IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + idx = FindIndex( + resistanceZone, + mXWZUnActivatedResistanceZones // + ); + hasResistance = !IsValidIndex(idx); + if (hasResistance) + { + // + lastResistance = resistanceZone; + + // + Add( + resistanceZone, + mXWZUnActivatedResistanceZones // + ); + } + } + else + { + // + idx = FindIndex( + resistanceZone, + mXWZActivatedResistanceZones // + ); + hasResistance = !IsValidIndex(idx); + if (hasResistance) + { + // + resistanceZone.To(activationBar.time); + + // + Add( + resistanceZone, + mXWZActivatedResistanceZones // + ); + } + } + + // + activationBar.Clean(); + } + } + + // + resistaneBar.Clean(); + } + + // +} + +// +void UpdatePOIs( + XOHCL &bar // +) +{ + // + int count = -1; + bool has = false; + bool resetDraws = false; + + // + if (!bar.IsValid()) + { + return; + } + + // + datetime to = bar.time; + + // + // Order Blocks ... + + // + count = ArraySize(mXWZUnActivatedOBs); + has = IsValidSize(count); + if (has) + { + // + XCOrderBlock *tmps[]; + for (int i = 0; i < count; i++) + { + // + // Update To ... + mXWZUnActivatedOBs[i].To(to); + + // + // Check Activation ... + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = mXWZUnActivatedOBs[i] + .IsActivated( + mXWZUnActivatedOBs[i].GetDirection(), + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + activationBar.Clean(); + + // + if (!isActivated) + { + // + Add( + mXWZUnActivatedOBs[i], + tmps // + ); + } + else + { + // + Add( + mXWZUnActivatedOBs[i], + mXWZActivatedOBs // + ); + } + } + + // + Copy( + tmps, + mXWZUnActivatedOBs // + ); + } + + // + count = ArraySize(mXWZActivatedOBs); + has = IsValidSize(count); + if (has) + { + // + // Remove UnWorks / Breaked Zones ... + int removeIDX[]; + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = mXWZActivatedOBs[i]; + + // + XOHCL passedBar; + bool isBodyOut = false; + ENUM_X_DIRECTION iForDir = iZone.GetDirection(); + + // + // Check Works ... + bool isWorked = iZone.IsWorked( + iForDir, + passedBar, + isBodyOut, + true, + false, + false, + _Period // + ); + if (!isWorked) + { + // + Add( + i, + removeIDX // + ); + + // + passedBar.Clean(); + break; + } + + // + passedBar.Clean(); + } + + // + if (HasChild(removeIDX)) + { + // + resetDraws = true; + + // + count = ArraySize(removeIDX); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + mXWZActivatedOBs, + removeIDX[i], + 1 // + ); + } + } + + // + Clean(removeIDX); + } + + // + // Fair Value Gaps ... + + // + count = ArraySize(mXWZUnActivatedFVGs); + has = IsValidSize(count); + if (has) + { + // + XCFVG *tmps[]; + for (int i = 0; i < count; i++) + { + // + // Update To ... + mXWZUnActivatedFVGs[i].To(to); + + // + // Check Activation ... + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = mXWZUnActivatedFVGs[i] + .IsActivated( + mXWZUnActivatedFVGs[i].GetDirection(), + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + activationBar.Clean(); + + // + if (!isActivated) + { + // + Add( + mXWZUnActivatedFVGs[i], + tmps // + ); + } + else + { + // + Add( + mXWZUnActivatedFVGs[i], + mXWZActivatedFVGs // + ); + } + } + + // + Copy( + tmps, + mXWZUnActivatedFVGs // + ); + } + + // + count = ArraySize(mXWZActivatedFVGs); + has = IsValidSize(count); + if (has) + { + // + // Remove UnWorks / Breaked Zones ... + int removeIDX[]; + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = mXWZActivatedFVGs[i]; + + // + XOHCL passedBar; + bool isBodyOut = false; + ENUM_X_DIRECTION iForDir = iZone.GetDirection(); + + // + // Check Works ... + bool isWorked = iZone.IsWorked( + iForDir, + passedBar, + isBodyOut, + true, + false, + false, + _Period // + ); + if (!isWorked) + { + // + Add( + i, + removeIDX // + ); + + // + passedBar.Clean(); + break; + } + + // + passedBar.Clean(); + } + + // + if (HasChild(removeIDX)) + { + // + resetDraws = true; + + // + count = ArraySize(removeIDX); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + mXWZActivatedFVGs, + removeIDX[i], + 1 // + ); + } + } + + // + Clean(removeIDX); + } + + // + // Support Zones ... + + // + count = ArraySize(mXWZUnActivatedSupportZones); + has = IsValidSize(count); + if (has) + { + // + XCSupportZone *tmps[]; + for (int i = 0; i < count; i++) + { + // + // Update To ... + mXWZUnActivatedSupportZones[i].To(to); + + // + // Check Activation ... + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = mXWZUnActivatedSupportZones[i] + .IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + Add( + mXWZUnActivatedSupportZones[i], + tmps // + ); + } + else + { + // + mXWZUnActivatedSupportZones[i].To(activationBar.time); + + // + Add( + mXWZUnActivatedSupportZones[i], + mXWZActivatedSupportZones // + ); + } + + // + activationBar.Clean(); + } + + // + Copy( + tmps, + mXWZUnActivatedSupportZones // + ); + } + + // + count = ArraySize(mXWZActivatedSupportZones); + has = IsValidSize(count); + if (has) + { + // + // Remove UnWorks / Breaked Zones ... + int removeIDX[]; + ENUM_X_DIRECTION iForDir = X_DIRECTION_BULLISH; + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = mXWZActivatedSupportZones[i]; + + // + XOHCL passedBar; + bool isBodyOut = false; + + // + // Check Works ... + bool isWorked = iZone.IsWorked( + iForDir, + passedBar, + isBodyOut, + true, + false, + false, + _Period // + ); + if (!isWorked) + { + // + Add( + i, + removeIDX // + ); + + // + passedBar.Clean(); + break; + } + + // + passedBar.Clean(); + } + + // + if (HasChild(removeIDX)) + { + // + resetDraws = true; + + // + count = ArraySize(removeIDX); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + mXWZActivatedSupportZones, + removeIDX[i], + 1 // + ); + } + } + + // + Clean(removeIDX); + } + + // + // Resistance Zones ... + + // + count = ArraySize(mXWZUnActivatedResistanceZones); + has = IsValidSize(count); + if (has) + { + // + XCResistanceZone *tmps[]; + for (int i = 0; i < count; i++) + { + // + // Update To ... + mXWZUnActivatedResistanceZones[i].To(to); + + // + // Check Activation ... + + // + // Check OB Not Activated ... + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = mXWZUnActivatedResistanceZones[i] + .IsActivated( + X_DIRECTION_BULLISH, + activationBar, + isActivationBarBodyIn, + false, + _Period // + ); + + // + if (!isActivated) + { + // + Add( + mXWZUnActivatedResistanceZones[i], + tmps // + ); + } + else + { + // + mXWZUnActivatedResistanceZones[i].To(activationBar.time); + + // + Add( + mXWZUnActivatedResistanceZones[i], + mXWZActivatedResistanceZones // + ); + } + + // + activationBar.Clean(); + } + + // + Copy( + tmps, + mXWZUnActivatedResistanceZones // + ); + } + + // + count = ArraySize(mXWZActivatedResistanceZones); + has = IsValidSize(count); + if (has) + { + // + // Remove UnWorks / Breaked Zones ... + int removeIDX[]; + ENUM_X_DIRECTION iForDir = X_DIRECTION_BEARISH; + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = mXWZActivatedResistanceZones[i]; + + // + XOHCL passedBar; + bool isBodyOut = false; + + // + // Check Breake ... + bool isBreaked = iZone.IsBreaked( + iForDir, + passedBar, + isBodyOut, + true, + false, + _Period // + ); + if (isBreaked) + { + // + Add( + i, + removeIDX // + ); + + // + passedBar.Clean(); + break; + } + + // + // Check Works ... + bool isWorked = iZone.IsWorked( + iForDir, + passedBar, + isBodyOut, + true, + false, + false, + _Period // + ); + if (!isWorked) + { + // + Add( + i, + removeIDX // + ); + + // + passedBar.Clean(); + break; + } + + // + passedBar.Clean(); + } + + // + if (HasChild(removeIDX)) + { + // + resetDraws = true; + + // + count = ArraySize(removeIDX); + for (int i = 0; i < count; i++) + { + // + ArrayRemove( + mXWZActivatedResistanceZones, + removeIDX[i], + 1 // + ); + } + } + + // + Clean(removeIDX); + } + + // + // + // + + // + // Clean Draws if has to ... + if (resetDraws) + { + mXWZDrawnObjects.Clear(); + } + + // +} + +// +void DrawPOIs() +{ + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + if (!showPOIs) + { + return; + } + + // + // Order Blocks ... + if (showOrderBlocks) + { + // + bool showBullishOrderBlocks = true; + bool showBearishOrderBlocks = true; + + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedOBs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + bool isBullish = mXWZUnActivatedOBs[i].IsBullish(); + + // + if ((isBullish && + showBullishOrderBlocks) || + (!isBullish && + showBearishOrderBlocks)) + { + // + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateOrderBlock( + mXWZUnActivatedOBs[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + + // + // Activated ... + count = ArraySize(mXWZActivatedOBs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iOB = mXWZActivatedOBs[i]; + + // + bool isBullish = iOB.IsBullish(); + + // + if (showActivatedPOIs && + ((isBullish && + showBullishOrderBlocks) || + (!isBullish && + showBearishOrderBlocks))) + { + // + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateOrderBlock( + iOB, + iObj // + ); + if (isCreated) + { + // + // if (isBullish) + // { + // ((XCBullishOrderBlockObject *)iObj).ZoneFill(true); + // } + // else + // { + // ((XCBearishOrderBlockObject *)iObj).ZoneFill(true); + // } + + // + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // + // Fair Value Gaps ... + if (showFairValueGaps) + { + // + bool showBullishFairValueGaps = true; + bool showBearishFairValueGaps = true; + + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedFVGs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + bool isBullish = mXWZUnActivatedFVGs[i].IsBullish(); + + // + if ((isBullish && + showBullishFairValueGaps) || + (!isBullish && + showBearishFairValueGaps)) + { + // + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateFairValueGap( + mXWZUnActivatedFVGs[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + + // + // Activated ... + count = ArraySize(mXWZActivatedFVGs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iFVG = mXWZActivatedFVGs[i]; + + // + bool isBullish = iFVG.IsBullish(); + + // + if (showActivatedPOIs && + ((isBullish && + showBullishFairValueGaps) || + (!isBullish && + showBearishFairValueGaps))) + { + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateFairValueGap( + iFVG, + iObj // + ); + if (isCreated) + { + // + // if (isBullish) + // { + // ((XCBullishOrderBlockObject *)iObj).ZoneFill(true); + // } + // else + // { + // ((XCBearishOrderBlockObject *)iObj).ZoneFill(true); + // } + + // + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // + // Support Zones ... + if (showSupportZones) + { + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedSupportZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateSupportZone( + mXWZUnActivatedSupportZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + + // + // Activated ... + if (showActivatedPOIs) + { + // + count = ArraySize(mXWZActivatedSupportZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateSupportZone( + mXWZActivatedSupportZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // + // Resistance Zones ... + if (showResistanceZones) + { + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedResistanceZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateResistanceZone( + mXWZUnActivatedResistanceZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + + // + // Activated ... + if (showActivatedPOIs) + { + // + count = ArraySize(mXWZActivatedResistanceZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateResistanceZone( + mXWZActivatedResistanceZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Documents/BKP/x-saherelm.xobfvg.lib.mq5 b/BKPS/14031218/Documents/BKP/x-saherelm.xobfvg.lib.mq5 new file mode 100644 index 0000000..3939603 --- /dev/null +++ b/BKPS/14031218/Documents/BKP/x-saherelm.xobfvg.lib.mq5 @@ -0,0 +1,1897 @@ +// /////////////////////////////////////////////////////// +// // +// // SaherElm IT Center MQL5 Seriallize Library +// // --------------------------------------- +// // Name: XOBFVGLib +// // Description: All models related to POIs ... +// // +// // +// // Maintainer: +// // ------------ +// // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// // +// ////////////////////////////////////////////////////// +// // +// // Global Properties ... +// #property library +// #property copyright "Copyright `023, SaherElm IT Center" +// #property link "https://www.saherelm.ir" +// #property version "1.00" +// #property strict + +// // +// // Imports ... +// #include "../Libraries/x-saherelm.x-poi.state.lib.mq5" + +// // +// struct XOBFVGPivot +// { +// // +// // Props ... +// double value; +// datetime at; + +// // +// // Constructor ... +// XOBFVGPivot() +// { +// Clean(); +// } + +// // +// // Tools ... + +// // +// void Clean() +// { +// // +// value = 0; +// at = NULL; + +// // +// ZeroMemory(this); +// } + +// // +// bool IsValid() +// { +// // +// bool result = false; + +// // +// result = +// value > 0 && +// IsValid(at); + +// // +// return result; +// } +// }; + +// // +// struct XOBFVG +// { +// // +// // Props ... +// XCFVG *fvg; +// XCOrderBlock *ob; + +// // +// XCSupplyZone *supplyZones[]; +// XCDemandZone *demandZones[]; + +// // +// XCSupportZone *supportZones[]; +// XCResistanceZone *resistanceZones[]; + +// // +// // Constructor ... +// XOBFVG() +// { +// Clean(); +// } + +// // +// // Tools ... + +// // +// void Clean() +// { +// // +// ZeroMemory(ob); +// ZeroMemory(fvg); + +// // +// Clean(supplyZones); +// Clean(demandZones); +// Clean(supportZones); +// Clean(resistanceZones); + +// // +// ZeroMemory(this); +// } + +// // +// bool IsValid() +// { +// return HasOB() && +// HasFVG(); +// } + +// // +// bool HasOB() +// { +// return ob != NULL && +// ob.IsValid(); +// } + +// // +// bool HasFVG() +// { +// return fvg != NULL && +// fvg.IsValid(); +// } + +// // +// bool HasSupplyZones() +// { +// return HasChild(supplyZones); +// } + +// // +// int CountSupplyZones() +// { +// return ArraySize(supplyZones); +// } + +// // +// bool HasDemandZones() +// { +// return HasChild(demandZones); +// } + +// // +// int CountDemandZones() +// { +// return ArraySize(demandZones); +// } + +// // +// bool HasSupportZones() +// { +// return HasChild(supportZones); +// } + +// // +// int CountSupportZones() +// { +// return ArraySize(supportZones); +// } + +// // +// bool HasResistanceZones() +// { +// return HasChild(resistanceZones); +// } + +// // +// int CountResistanceZones() +// { +// return ArraySize(resistanceZones); +// } + +// // +// ENUM_X_DIRECTION GetDirection() +// { +// // +// ENUM_X_DIRECTION result = X_DIRECTION_NONE; + +// // +// bool isValid = IsValid(); +// if (!isValid) +// { +// return result; +// } + +// // +// result = ob.GetDirection(); + +// // +// return result; +// } + +// // +// bool IsBullish() +// { +// return IsBullish(GetDirection()); +// } + +// // +// bool IsBearish() +// { +// return IsBearish(GetDirection()); +// } + +// // +// int GetSwings( +// XOBFVGPivot &pivots[] // +// ) +// { +// // +// int result = 0; + +// // +// Clean(pivots); + +// // +// if (!IsValid()) +// { +// return result; +// } + +// // +// ENUM_X_DIRECTION forDir = GetDirection(); +// bool isBullish = IsBullish(forDir); + +// // +// XOHCL passedBar; +// XOBFVGPivot iPivot; +// bool isPassed = false; +// double appliedPrice = 0; +// bool isBodyState = false; + +// // +// // Start ... +// isPassed = ob.IsStarted( +// forDir, +// passedBar, +// isBodyState // +// ); +// if (isPassed) +// { +// // +// appliedPrice = +// isBullish +// ? passedBar.low +// : passedBar.high; + +// // +// iPivot.Clean(); +// iPivot.value = appliedPrice; +// iPivot.at = passedBar.time; + +// // +// AddRef( +// iPivot, +// pivots // +// ); + +// // +// iPivot.Clean(); +// } + +// // +// // Activation ... +// isPassed = ob.IsActivated( +// forDir, +// passedBar, +// isBodyState // +// ); +// if (isPassed) +// { +// // +// appliedPrice = +// isBullish +// ? passedBar.low +// : passedBar.high; + +// // +// iPivot.Clean(); +// iPivot.value = appliedPrice; +// iPivot.at = passedBar.time; + +// // +// AddRef( +// iPivot, +// pivots // +// ); + +// // +// iPivot.Clean(); +// } + +// // +// // Worked ... +// isPassed = ob.IsWorked( +// forDir, +// passedBar, +// isBodyState // +// ); +// if (isPassed) +// { +// // +// appliedPrice = +// isBullish +// ? passedBar.low +// : passedBar.high; + +// // +// iPivot.Clean(); +// iPivot.value = appliedPrice; +// iPivot.at = passedBar.time; + +// // +// AddRef( +// iPivot, +// pivots // +// ); + +// // +// iPivot.Clean(); +// } + +// // +// passedBar.Clean(); + +// // +// result = ArraySize(pivots); + +// // +// return result; +// } + +// // +// void UpdateZones( +// XPOIState &state // +// ) +// { +// // +// Clean(supplyZones); +// Clean(demandZones); +// Clean(supportZones); +// Clean(resistanceZones); + +// // +// bool isValid = +// IsValid() && +// state.HasChild(); +// if (!isValid) +// { +// return; +// } + +// // +// int count = 0; +// bool has = false; +// bool isPassed = false; + +// // +// // Supply Zones ... +// has = state.HasSupplyZones(); +// if (has) +// { +// // +// count = state.CountSupplyZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCSupplyZone *iZone = state.supplyZones[i]; + +// // +// isPassed = iZone.From() > ob.From(); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// isPassed = IsInsideDiff( +// iZone, +// ob // +// ); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// Add( +// iZone, +// supplyZones // +// ); +// } +// } + +// // +// // Demand Zones ... +// has = state.HasDemandZones(); +// if (has) +// { +// // +// count = state.CountDemandZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCDemandZone *iZone = state.demandZones[i]; + +// // +// isPassed = iZone.From() > ob.From(); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// isPassed = IsInsideDiff( +// iZone, +// ob // +// ); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// Add( +// iZone, +// demandZones // +// ); +// } +// } + +// // +// // Support Zones ... +// has = state.HasSupportZones(); +// if (has) +// { +// // +// count = state.CountSupportZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCSupportZone *iZone = state.supportZones[i]; + +// // +// isPassed = iZone.From() > ob.From(); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// isPassed = IsInsideDiff( +// iZone, +// ob // +// ); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// Add( +// iZone, +// supportZones // +// ); +// } +// } + +// // +// // Resistance Zones ... +// has = state.HasResistanceZones(); +// if (has) +// { +// // +// count = state.CountResistanceZones(); +// for (int i = 0; i < count; i++) +// { +// // +// XCResistanceZone *iZone = state.resistanceZones[i]; + +// // +// isPassed = iZone.From() > ob.From(); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// isPassed = IsInsideDiff( +// iZone, +// ob // +// ); +// if (!isPassed) +// { +// // +// ZeroMemory(iZone); +// continue; +// } + +// // +// Add( +// iZone, +// resistanceZones // +// ); +// } +// } +// } + +// // +// void UpdateTo(datetime value = NULL) +// { +// // +// value = NormalizeTime(value); + +// // +// int count = 0; +// bool has = false; + +// // +// has = HasOB(); +// if (has) +// { +// ob.To(value); +// } + +// // +// has = HasFVG(); +// if (has) +// { +// fvg.To(value); +// } + +// // +// // Supply Zones ... +// has = HasSupplyZones(); +// if (has) +// { +// // +// count = CountSupplyZones(); +// for (int i = 0; i < count; i++) +// { +// supplyZones[i].To(value); +// } +// } + +// // +// // Demand Zones ... +// has = HasDemandZones(); +// if (has) +// { +// // +// count = CountDemandZones(); +// for (int i = 0; i < count; i++) +// { +// demandZones[i].To(value); +// } +// } + +// // +// // Support Zones ... +// has = HasSupportZones(); +// if (has) +// { +// // +// count = CountSupportZones(); +// for (int i = 0; i < count; i++) +// { +// supportZones[i].To(value); +// } +// } + +// // +// // Resistance Zones ... +// has = HasResistanceZones(); +// if (has) +// { +// // +// count = CountResistanceZones(); +// for (int i = 0; i < count; i++) +// { +// resistanceZones[i].To(value); +// } +// } +// } +// }; + +// // +// // +// // + +// /** +// * Extract XOBFVG Collection of Market ... +// * +// * @param htfState: Higher Time Frame POI State (Used For Detecting Order Blocks) ... +// * @param mtfState: Medium Time Frame POI State (Used For Detecting Fair Value Gaps) ... +// * @param stfState: Short Time Frame POI State (Used For Detecting Other POI(s)) ... +// * @param dest: Result Collection ... +// * @param forDir: Market Direction for Detecting POI(s) ... +// * @param forPeriod: Time Frame which Used for Zones actions (NULL for Default) ... +// * @param startState: Zones Start State ... +// * @param forceStartedBodyOut: Zones Started Bar's Body State ... +// * @param activeState: Zones Activation State ... +// * @param forceActivatedBodyIn: Zones Activated Bar's Body State ... +// * @param breakState: Zones Breaked State ... +// * @param forceBreakedBodyOut: Zone Breaker Bar's Body State ... +// * @param workState: Zones Worked State ... +// * @param forceWorkedBodyOut: Zones Worked Bar's Body State ... +// * @param applySort: Specify Applying Sorting on Collections ... +// * @param applyFromFilter: Filter Sorted Zones based on Occured Date ... +// * @param applyPlaceFilter: Filter Sorted Zones based on Occured Place ... +// * @param ignoreInside: Ignore Inside Sides of POI(s) Zones in Related to Order Block ... +// * @param applyFromFilterForPOIs: Apply From Filter for Other POI(s) ... +// * +// * @return ( int ) +// */ +// int ExtractOBFVGZones( +// XPOIState &htfState, +// XPOIState &mtfState, +// XPOIState &stfState, +// XOBFVG &dest[], +// // +// ENUM_X_DIRECTION forDir, +// ENUM_TIMEFRAMES forPeriod = NULL, +// // +// // Start ... +// ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, +// bool forceStartedBodyOut = false, +// // +// // Activation ... +// ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, +// bool forceActivatedBodyIn = false, +// // +// // Breaktion ... +// ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, +// bool forceBreakedBodyOut = false, +// // +// // Works ... +// ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, +// bool forceWorkedBodyOut = false, +// // +// bool applySort = true, +// bool applyFromFilter = true, +// bool applyPlaceFilter = true, +// // +// bool ignoreInside = true, +// // +// bool detectInsideOBPOIs = true, +// bool detectInsideFVGPOIs = true, +// bool applyFromFilterForPOIs = true +// // +// ) +// { +// // +// int result = 0; + +// // +// Clean(dest); + +// // +// bool isValid = +// // +// htfState.HasChild() && +// mtfState.HasChild() && +// stfState.HasChild() && +// HasDirection(forDir) +// // +// ; +// if (!isValid) +// { +// return result; +// } + +// // +// // Implement Logic ... + +// // +// int idx = -1; +// int count = 0; +// bool has = false; +// XCFVG *tmpFVGs[]; +// XOBFVG tmpOBFVGs[]; +// XCOrderBlock *tmpOBs[]; +// XCOrderBlock *tmpWorkingOBs[]; +// datetime cTime = TimeCurrent(); +// bool isBullish = IsBullish(forDir); + +// // +// if (isBullish) +// { +// // +// has = htfState.HasBullishOrderBlocks(); +// if (has) +// { +// // +// Copy( +// htfState.bullishOrderBlocks, +// tmpOBs // +// ); + +// // +// has = mtfState.HasBullishFairValueGaps(); +// if (has) +// { +// // +// Copy( +// mtfState.bullishFairValueGaps, +// tmpFVGs // +// ); +// } +// } +// } +// else +// { +// // +// has = htfState.HasBearishOrderBlocks(); +// if (has) +// { +// // +// Copy( +// htfState.bearishOrderBlocks, +// tmpOBs // +// ); + +// // +// has = mtfState.HasBearishFairValueGaps(); +// if (has) +// { +// // +// Copy( +// mtfState.bearishFairValueGaps, +// tmpFVGs // +// ); +// } +// } +// } + +// // +// count = ArraySize(tmpOBs); +// has = IsValidSize(count); +// if (has) +// { +// // +// for (int i = 0; i < count; i++) +// { +// // +// XCOrderBlock *iOB = tmpOBs[i]; + +// // +// // Check Started State ... +// if (startState == XZONE_STATE_PASSED || +// startState == XZONE_STATE_FAILED) +// { +// // +// XOHCL passedBar; +// bool isBodyOut = false; +// bool isStarted = iOB.IsStarted( +// forDir, +// passedBar, +// isBodyOut, +// forPeriod // +// ); + +// // +// bool isPassed = +// startState == XZONE_STATE_FAILED +// ? !isStarted +// : !forceStartedBodyOut +// ? isStarted +// : isStarted && +// isBodyOut; + +// // +// passedBar.Clean(); +// if (!isPassed) +// { +// continue; +// } +// } + +// // +// // Check Activation State ... +// if (activeState == XZONE_STATE_PASSED || +// activeState == XZONE_STATE_FAILED) +// { +// // +// XOHCL passedBar; +// bool isBodyIn = false; +// bool isActivated = iOB.IsActivated( +// forDir, +// passedBar, +// isBodyIn, +// forceStartedBodyOut, +// forPeriod // +// ); + +// // +// bool isPassed = +// activeState == XZONE_STATE_FAILED +// ? !isActivated +// : !forceActivatedBodyIn +// ? isActivated +// : isActivated && +// isBodyIn; + +// // +// passedBar.Clean(); +// if (!isPassed) +// { +// continue; +// } +// } + +// // +// // Check Break State ... +// if (breakState == XZONE_STATE_PASSED || +// breakState == XZONE_STATE_FAILED) +// { +// // +// XOHCL passedBar; +// bool isBodyOut = false; +// bool isBreaked = iOB.IsBreaked( +// forDir, +// passedBar, +// isBodyOut, +// forceStartedBodyOut, +// forPeriod // +// ); + +// // +// bool isPassed = +// breakState == XZONE_STATE_FAILED +// ? !isBreaked +// : !forceBreakedBodyOut +// ? isBreaked +// : isBreaked && +// isBodyOut; + +// // +// passedBar.Clean(); +// if (!isPassed) +// { +// continue; +// } +// } + +// // +// // Check Work State ... +// if (workState == XZONE_STATE_PASSED || +// workState == XZONE_STATE_FAILED) +// { +// // +// bool ignoreActivation = activeState != XZONE_STATE_PASSED; + +// // +// XOHCL passedBar; +// bool isBodyOut = false; +// bool isWorked = iOB.IsWorked( +// forDir, +// passedBar, +// isBodyOut, +// ignoreActivation, +// forceStartedBodyOut, +// forceActivatedBodyIn, +// forPeriod // +// ); + +// // +// bool isPassed = +// workState == XZONE_STATE_FAILED +// ? !isWorked +// : !forceWorkedBodyOut +// ? isWorked +// : isWorked && +// isBodyOut; + +// // +// passedBar.Clean(); +// if (!isPassed) +// { +// continue; +// } +// } + +// // +// has = FindIndex( +// idx, +// iOB, +// tmpWorkingOBs // +// ); +// if (has) +// { +// // +// ZeroMemory(iOB); +// continue; +// } + +// // +// Add( +// iOB, +// tmpWorkingOBs // +// ); +// } +// } + +// // +// // Clean ... +// Clean(tmpOBs); +// has = HasChild(tmpWorkingOBs); +// if (has) +// { +// // +// Clean(tmpOBs); +// Copy( +// tmpWorkingOBs, +// tmpOBs // +// ); + +// // +// Clean(tmpWorkingOBs); +// } + +// // +// // Sorting ... +// if (applySort) +// { +// // +// Clean(tmpWorkingOBs); +// has = HasChild(tmpOBs); +// count = ArraySize(tmpOBs); + +// // +// // Sorting Applied Only when there is more than one item ... +// if (has && count > 1) +// { +// // +// bool hasLast = false; +// XCOrderBlock *last = NULL; +// while (HasChild(tmpOBs)) +// { +// // +// // Extract First Last Item ... +// if (!hasLast) +// { +// // +// idx = +// isBullish +// ? GetLowest(tmpOBs) +// : GetHighest(tmpOBs); +// hasLast = IsValidIndex(idx); +// if (hasLast) +// { +// // +// last = tmpOBs[idx]; +// ArrayRemove( +// tmpOBs, +// idx, +// 1 // +// ); + +// // +// Add( +// last, +// tmpWorkingOBs // +// ); +// } +// } + +// // +// has = false; +// XCOrderBlock *iOB = NULL; +// idx = +// isBullish +// ? GetLowest(tmpOBs) +// : GetHighest(tmpOBs); +// has = IsValidIndex(idx); +// if (has) +// { +// // +// iOB = tmpOBs[idx]; +// ArrayRemove( +// tmpOBs, +// idx, +// 1 // +// ); +// } + +// // +// if (!has) +// { +// break; +// } + +// // +// // Apply From Filter ... +// if (applyFromFilter) +// { +// // +// bool isFromPassed = +// hasLast && +// last.From() < iOB.From(); +// if (!isFromPassed) +// { +// continue; +// } +// } + +// // +// // Apply Place Filter ... +// if (applyPlaceFilter) +// { +// // +// bool isAbove = +// hasLast && +// IsAbove( +// iOB, +// last, +// ignoreInside // +// ); + +// // +// bool isBelow = +// hasLast && +// IsBelow( +// iOB, +// last, +// ignoreInside // +// ); + +// // +// bool isPlacePassed = +// isBullish +// ? isAbove +// : isBelow; +// if (!isPlacePassed) +// { +// continue; +// } +// } + +// // +// last = iOB; +// Add( +// iOB, +// tmpWorkingOBs // +// ); +// } + +// // +// if (hasLast && +// !HasChild(tmpWorkingOBs)) +// { +// // +// Add( +// last, +// tmpWorkingOBs // +// ); +// } +// } +// else +// { +// // +// Copy( +// tmpOBs, +// tmpWorkingOBs // +// ); +// } + +// // +// if (HasChild(tmpWorkingOBs)) +// { +// // +// Copy( +// tmpWorkingOBs, +// tmpOBs // +// ); +// } +// // +// } + +// // +// count = ArraySize(tmpOBs); +// has = IsValidSize(count); + +// // +// // Converts to XOBFVG ... +// if (has) +// { +// // +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG; + +// // +// iOBFVG.ob = tmpOBs[i]; + +// // +// AddRef( +// iOBFVG, +// tmpOBFVGs // +// ); + +// // +// iOBFVG.Clean(); +// } +// } + +// // +// Clean(dest); +// Clean(tmpOBs); +// Clean(tmpWorkingOBs); + +// // +// // Here we Going to Complete XOBFVGs ... +// has = HasChild(tmpOBFVGs); +// if (has && HasChild(tmpFVGs)) +// { +// // +// count = ArraySize(tmpOBFVGs); +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG = tmpOBFVGs[i]; + +// // +// // Detecting FVG ... +// XCFVG *tmpWorkingFVGs[]; +// for (int j = 0; j < ArraySize(tmpFVGs); j++) +// { +// // +// XCFVG *jFVG = tmpFVGs[j]; + +// // +// // Check Start Date ... +// bool isFromPassed = jFVG.From() > iOBFVG.ob.From(); +// if (!isFromPassed) +// { +// // +// ZeroMemory(jFVG); +// continue; +// } + +// // +// // Check Place ... + +// // +// bool isAbove = IsAboveDiff( +// jFVG, +// iOBFVG.ob, +// ignoreInside // +// ); + +// // +// bool isBelow = IsBelowDiff( +// jFVG, +// iOBFVG.ob, +// ignoreInside // +// ); + +// // +// bool isInside = IsInsideDiff( +// jFVG, +// iOBFVG.ob, +// false // +// ); + +// // +// bool isPlacePassed = +// isInside || +// (isBullish +// ? isAbove +// : isBelow); +// if (!isPlacePassed) +// { +// // +// ZeroMemory(jFVG); +// continue; +// } + +// // +// Add( +// jFVG, +// tmpWorkingFVGs // +// ); +// } + +// // +// int fvgsCount = ArraySize(tmpWorkingFVGs); +// has = IsValidSize(fvgsCount); +// if (has) +// { +// // +// idx = +// isBullish +// ? GetLowest(tmpWorkingFVGs) +// : GetHighest(tmpWorkingFVGs); + +// // +// if (IsValidIndex(idx)) +// { +// // +// XCFVG *selectedFVG = tmpWorkingFVGs[idx]; + +// // +// iOBFVG.fvg = selectedFVG; + +// // +// bool isExists = FindIndex( +// idx, +// selectedFVG, +// tmpFVGs // +// ); +// if (isExists) +// { +// // +// ArrayRemove( +// tmpFVGs, +// idx, +// 1 // +// ); +// } +// } +// } +// Clean(tmpWorkingFVGs); + +// // +// bool isFVGPassed = iOBFVG.HasFVG(); +// if (!isFVGPassed) +// { +// // +// iOBFVG.Clean(); +// continue; +// } + +// // +// // Validate Model ... +// bool isValid = iOBFVG.IsValid(); +// if (!isValid) +// { +// // +// iOBFVG.Clean(); +// continue; +// } + +// // +// iOBFVG.UpdateTo(cTime); + +// // +// AddRef( +// iOBFVG, +// dest // +// ); + +// // +// iOBFVG.Clean(); +// } + +// // +// Clean(tmpOBFVGs); +// } + +// // +// // Detecting Other POI(s) ... +// has = HasChild(dest); +// bool canDetectPOIs = +// detectInsideOBPOIs || +// detectInsideFVGPOIs; +// if (has && +// canDetectPOIs) +// { +// // +// count = ArraySize(dest); +// for (int i = 0; i < count; i++) +// { +// // +// // Supply Zones ... +// has = stfState.HasSupplyZones(); +// if (has) +// { +// // +// for (int j = 0; j < stfState.CountSupplyZones(); j++) +// { +// // +// bool isInsideOB = IsInsideDiff( +// stfState.supplyZones[j], +// dest[i].ob // +// ); + +// // +// bool isInsideFVG = IsInsideDiff( +// stfState.supplyZones[j], +// dest[i].fvg // +// ); + +// // +// bool isInside = isInsideOB || +// isInsideFVG; +// if (isInside) +// { +// // +// bool isPassed = +// detectInsideOBPOIs +// ? isInsideOB +// : detectInsideFVGPOIs +// ? isInsideFVG +// : false; +// if (isPassed) +// { +// // +// isPassed = +// !applyFromFilterForPOIs +// ? isPassed +// : isInsideOB +// ? stfState.supplyZones[j].From() > dest[i].ob.From() +// : isInsideFVG +// ? stfState.supplyZones[j].From() > dest[i].fvg.From() +// : false; +// } + +// // +// if (isPassed) +// { +// // +// Add( +// stfState.supplyZones[j], +// dest[i].supplyZones // +// ); +// } +// } +// } +// } + +// // +// // Demand Zones ... +// has = stfState.HasDemandZones(); +// if (has) +// { +// // +// for (int j = 0; j < stfState.CountDemandZones(); j++) +// { +// // +// bool isInsideOB = IsInsideDiff( +// stfState.demandZones[j], +// dest[i].ob // +// ); + +// // +// bool isInsideFVG = IsInsideDiff( +// stfState.demandZones[j], +// dest[i].fvg // +// ); + +// // +// bool isInside = isInsideOB || +// isInsideFVG; +// if (isInside) +// { +// // +// bool isPassed = +// detectInsideOBPOIs +// ? isInsideOB +// : detectInsideFVGPOIs +// ? isInsideFVG +// : false; +// if (isPassed) +// { +// // +// isPassed = +// !applyFromFilterForPOIs +// ? isPassed +// : isInsideOB +// ? stfState.demandZones[j].From() > dest[i].ob.From() +// : isInsideFVG +// ? stfState.demandZones[j].From() > dest[i].fvg.From() +// : false; +// } + +// // +// if (isPassed) +// { +// // +// Add( +// stfState.demandZones[j], +// dest[i].demandZones // +// ); +// } +// } +// } +// } + +// // +// // Support Zones ... +// has = stfState.HasSupportZones(); +// if (has) +// { +// // +// for (int j = 0; j < stfState.CountSupportZones(); j++) +// { +// // +// bool isInsideOB = IsInsideDiff( +// stfState.supportZones[j], +// dest[i].ob // +// ); + +// // +// bool isInsideFVG = IsInsideDiff( +// stfState.supportZones[j], +// dest[i].fvg // +// ); + +// // +// bool isInside = isInsideOB || +// isInsideFVG; +// if (isInside) +// { +// // +// bool isPassed = +// detectInsideOBPOIs +// ? isInsideOB +// : detectInsideFVGPOIs +// ? isInsideFVG +// : false; +// if (isPassed) +// { +// // +// isPassed = +// !applyFromFilterForPOIs +// ? isPassed +// : isInsideOB +// ? stfState.supportZones[j].From() > dest[i].ob.From() +// : isInsideFVG +// ? stfState.supportZones[j].From() > dest[i].fvg.From() +// : false; +// } + +// // +// if (isPassed) +// { +// // +// Add( +// stfState.supportZones[j], +// dest[i].supportZones // +// ); +// } +// } +// } +// } + +// // +// // Resistance Zones ... +// has = stfState.HasResistanceZones(); +// if (has) +// { +// // +// for (int j = 0; j < stfState.CountResistanceZones(); j++) +// { +// // +// bool isInsideOB = IsInsideDiff( +// stfState.resistanceZones[j], +// dest[i].ob // +// ); + +// // +// bool isInsideFVG = IsInsideDiff( +// stfState.resistanceZones[j], +// dest[i].fvg // +// ); + +// // +// bool isInside = isInsideOB || +// isInsideFVG; +// if (isInside) +// { +// // +// bool isPassed = +// detectInsideOBPOIs +// ? isInsideOB +// : detectInsideFVGPOIs +// ? isInsideFVG +// : false; +// if (isPassed) +// { +// // +// isPassed = +// !applyFromFilterForPOIs +// ? isPassed +// : isInsideOB +// ? stfState.resistanceZones[j].From() > dest[i].ob.From() +// : isInsideFVG +// ? stfState.resistanceZones[j].From() > dest[i].fvg.From() +// : false; +// } + +// // +// if (isPassed) +// { +// // +// Add( +// stfState.resistanceZones[j], +// dest[i].resistanceZones // +// ); +// } +// } +// } +// } +// } +// } + +// // +// Clean(tmpOBs); +// Clean(tmpFVGs); +// Clean(tmpOBFVGs); + +// // +// result = ArraySize(dest); + +// // +// return result; +// } + +// /** +// * Find Highest Order Block of XOBFVG Collection ... +// * +// * @param source: XOBFVG Collection ... +// * +// * @return ( int ) +// */ +// int GetHighest( +// XOBFVG &source[] // +// ) +// { +// // +// int result = -1; + +// // +// int count = ArraySize(source); +// bool has = IsValidSize(count); +// if (!has) +// { +// return result; +// } + +// // +// XOBFVG item; +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG = source[i]; + +// // +// bool canSet = +// !item.IsValid() +// ? true +// : item.ob.Upper() < iOBFVG.ob.Upper(); +// if (canSet) +// { +// // +// item = iOBFVG; +// result = i; +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// item.Clean(); + +// // +// return result; +// } + +// /** +// * Find Lowest Order Block of XOBFVG Collection ... +// * +// * @param source: XOBFVG Collection ... +// * +// * @return ( int ) +// */ +// int GetLowest( +// XOBFVG &source[] // +// ) +// { +// // +// int result = -1; + +// // +// int count = ArraySize(source); +// bool has = IsValidSize(count); +// if (!has) +// { +// return result; +// } + +// // +// XOBFVG item; +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG = source[i]; + +// // +// bool canSet = +// !item.IsValid() +// ? true +// : item.ob.Lower() > iOBFVG.ob.Lower(); +// if (canSet) +// { +// // +// item = iOBFVG; +// result = i; +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// item.Clean(); + +// // +// return result; +// } + +// /** +// * Find Youngest Order Block of XOBFVG Collection ... +// * +// * @param source: XOBFVG Collection ... +// * +// * @return ( int ) +// */ +// int GetYoungest( +// XOBFVG &source[] // +// ) +// { +// // +// int result = -1; + +// // +// int count = ArraySize(source); +// bool has = IsValidSize(count); +// if (!has) +// { +// return result; +// } + +// // +// XOBFVG item; +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG = source[i]; + +// // +// bool canSet = +// !item.IsValid() +// ? true +// : item.ob.From() < iOBFVG.ob.From(); +// if (canSet) +// { +// // +// item = iOBFVG; +// result = i; +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// item.Clean(); + +// // +// return result; +// } + +// /** +// * Find Oldest Order Block of XOBFVG Collection ... +// * +// * @param source: XOBFVG Collection ... +// * +// * @return ( int ) +// */ +// int GetOldest( +// XOBFVG &source[] // +// ) +// { +// // +// int result = -1; + +// // +// int count = ArraySize(source); +// bool has = IsValidSize(count); +// if (!has) +// { +// return result; +// } + +// // +// XOBFVG item; +// for (int i = 0; i < count; i++) +// { +// // +// XOBFVG iOBFVG = source[i]; + +// // +// bool canSet = +// !item.IsValid() +// ? true +// : item.ob.From() > iOBFVG.ob.From(); +// if (canSet) +// { +// // +// item = iOBFVG; +// result = i; +// } + +// // +// iOBFVG.Clean(); +// } + +// // +// item.Clean(); + +// // +// return result; +// } + +// /** +// * Sort XOBFVG Collection based on OB Place ... +// * +// * @param source: XOBFVG instance Collection ... +// * @param forDir: ENUM_X_DIRECTION member ... +// * @param ignoreInside: Specified Ignoring price inside in Sorting ... +// */ +// void Sort( +// XOBFVG &source[], +// ENUM_X_DIRECTION forDir, +// bool ignoreInside = true // +// ) +// { +// // +// int idx = -1; +// int count = 0; +// bool has = false; + +// // +// has = HasDirection(forDir); +// if (!has) +// { +// return; +// } + +// // +// bool isBullish = IsBullish(forDir); + +// // +// count = ArraySize(source); +// has = IsValidSize(count); +// if (!has) +// { +// return; +// } + +// // +// XOBFVG last; +// XOBFVG tmpItems[]; +// bool hasLast = false; +// while (HasChild(source)) +// { +// // +// if (!hasLast) +// { +// // +// idx = GetOldest(source); +// hasLast = IsValidIndex(idx); +// if (hasLast) +// { +// // +// last = source[idx]; +// ArrayRemove( +// source, +// idx, +// 1 // +// ); + +// // +// AddRef( +// last, +// tmpItems // +// ); +// } + +// // +// count = ArraySize(source); +// has = IsValidSize(count); +// if (!has) +// { +// // +// last.Clean(); +// break; +// } +// } +// if (!hasLast) +// { +// // +// last.Clean(); +// break; +// } + +// // +// XOBFVG item; +// idx = GetOldest(source); +// has = IsValidIndex(idx); +// if (!has) +// { +// // +// item.Clean(); +// last.Clean(); +// break; +// } +// item = source[idx]; +// ArrayRemove( +// source, +// idx, +// 1 // +// ); + +// // +// bool isAbove = IsAbove( +// item.ob, +// last.ob, +// ignoreInside // +// ); + +// // +// bool isBelow = IsBelow( +// item.ob, +// last.ob, +// ignoreInside // +// ); + +// // +// has = +// isBullish +// ? isAbove +// : isBelow; +// if (has) +// { +// // +// AddRef( +// item, +// tmpItems // +// ); + +// // +// last = item; +// hasLast = item.IsValid(); +// } +// } + +// // +// Clean(source); +// Copy( +// tmpItems, +// source // +// ); + +// // +// Clean(tmpItems); +// } + +// // diff --git a/BKPS/14031218/Documents/Diagrams/Position Protection.drawio b/BKPS/14031218/Documents/Diagrams/Position Protection.drawio new file mode 100644 index 0000000..d425cb2 --- /dev/null +++ b/BKPS/14031218/Documents/Diagrams/Position Protection.drawio @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKPS/14031218/Documents/JsModules/x-color.tools.js b/BKPS/14031218/Documents/JsModules/x-color.tools.js new file mode 100644 index 0000000..c3ac5f9 --- /dev/null +++ b/BKPS/14031218/Documents/JsModules/x-color.tools.js @@ -0,0 +1,506 @@ +/** + * XColor Tools Module ... + * a module for handle colorify text contents in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const XValueTools = require("./x-value.tools"); +//#endregion + +// +//#region Constants ... +/** + * these are available style which can applied to an string ... + */ +const AVAILABLE_STYLES = { + // + Bold: "\x1b[1m", + Dim: "\x1b[2m", + Underlined: "\x1b[4m", + Blink: "\x1b[5m", + ReverseFandB: "\x1b[7m", + Hidden: "\x1b[8m", + // + // Commonly used for reset all Styles ... + Reset: "\x1b[0m" +}; + +/** + * these are available foreground colors which can applied to an string ... + */ +const AVAILABLE_FOREGROUND_COLORS = { + Default: "\x1b[39m", + Black: "\x1b[30m", + Red: "\x1b[31m", + Green: "\x1b[32m", + Yellow: "\x1b[33m", + Blue: "\x1b[34m", + Magenta: "\x1b[35m", + Cyan: "\x1b[36m", + LightGray: "\x1b[37m", + DarkGray: "\x1b[90m", + LightRed: "\x1b[91m", + LightGreen: "\x1b[92m", + LightYellow: "\x1b[93m", + LightBlue: "\x1b[94m", + LightMagenta: "\x1b[95m", + LightCyan: "\x1b[96m", + White: "\x1b[97m", +}; + +/** + * these are available background colors which can applied to an string ... + */ +const AVAILABLE_BACKGROUND_COLORS = { + Default: "\x1b[49m", + Black: "\x1b[40m", + Red: "\x1b[41m", + Green: "\x1b[42m", + Yellow: "\x1b[43m", + Blue: "\x1b[44m", + Magenta: "\x1b[45m", + Cyan: "\x1b[46m", + LightGray: "\x1b[47m", + DarkGray: "\x1b[100m", + LightRed: "\x1b[101m", + LightGreen: "\x1b[102m", + LightYellow: "\x1b[103m", + LightBlue: "\x1b[104m", + LightMagenta: "\x1b[105m", + LightCyan: "\x1b[106m", + White: "\x1b[107m", +}; + +/** + * these are available style names, which exports from module and + * users can use them ... + */ +const STYLE_NAMES = { + Bold: "Bold", + Dim: "Dim", + Underlined: "Underlined", + Blink: "Blink", + ReverseFandB: "ReverseFandB", + Hidden: "Hidden", + Reset: "Reset", +}; + +/** + * these are available color names, which exports from module and + * users can use them ... + */ +const COLOR_NAMES = { + Default: "Default", + Black: "Black", + Red: "Red", + Green: "Green", + Yellow: "Yellow", + Blue: "Blue", + Magenta: "Magenta", + Cyan: "Cyan", + LightGray: "LightGray", + DarkGray: "DarkGray", + LightRed: "LightRed", + LightGreen: "LightGreen", + LightYellow: "LightYellow", + LightBlue: "LightBlue", + LightMagenta: "LightMagenta", + LightCyan: "LightCyan", + White: "White", +}; +//#endregion + +// +//#region Actions ... +/** + * apply specified style and color on a content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} styled content ... + */ +function apply( + content, + color, + style, + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}${AVAILABLE_STYLES.Reset}`; + } + +} + +/** + * apply specific style on a content ... + * + * @param {string} content specific content which going to styled ... + * @param {string} style a member of STYLE_NAMES which specified that which style going to applied to content ... + * @returns {string} styled content ... + */ +function applyStyle(content, style) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eStyle = AVAILABLE_STYLES[style]; + if (eStyle === undefined) { + return content; + } + + // + return `${eStyle}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific foreground color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyForegroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_FOREGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific background color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyBackgroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_BACKGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * generate style and color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} style and color applier string ... + */ +function getApplier( + style = "", + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate style applier expression ... + * + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @returns {string} style applier string ... + */ +function getStyleApplier( + style = "", + reset = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} color applier string ... + */ +function getColorApplier( + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * colorified specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} + */ +function colorifyContent( + content = "", + color = "", + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Finde Colors ... + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}`; + } + + // + if ( + result.length > 0 + && ( + XValueTools.isValidArg(eFColor) || + XValueTools.isValidArg(eBColor) + ) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * apply style on specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} style soecufic style name to use ... + * @returns {string} + */ +function stylifiyContent( + content = "", + style = "", +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}`; + } + + // + if ( + result.length > 0 + && XValueTools.isValidArg(eStyle) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + STYLE_NAMES, + COLOR_NAMES, + // + apply, + applyStyle, + getApplier, + getColorApplier, + getStyleApplier, + colorifyContent, + stylifiyContent, + applyForegroundColor, + applyBackgroundColor, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031218/Documents/JsModules/x-file.tools.js b/BKPS/14031218/Documents/JsModules/x-file.tools.js new file mode 100644 index 0000000..2a3535d --- /dev/null +++ b/BKPS/14031218/Documents/JsModules/x-file.tools.js @@ -0,0 +1,887 @@ +/** + * XFile Tools Module ... + * a module for handle all file/folder manipulating task in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const fs = require('fs'); +const os = require('os'); +const Path = require('path'); +const http = require('http'); +const https = require('https'); +const XValueTools = require('./x-value.tools'); +//#endregion + +// +//#region Constants ... +/** + * current os path separators ... + */ +const PathSeparator = Path.sep; + +/** + * current directory ... + */ +const CurrentDir = __dirname; +//#endregion + +// +//#region Actions ... +// +//#region Global ... +/** + * retrieve a path status ... + * + * @param {string} path a path value to check ... + * @returns an stat object ... + */ +function getStatus(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return undefined; + } + + // + return fs.statSync(path); +} + +/** + * retrieve user's Home path ... + * + * @returns {string} a path ... + */ +function getHomePath() { + return os.homedir(); +} +//#endregion + +// +//#region Path ... +/** + * retrieve the base name of specific address path ... + * + * @param {string} path address of file or folder ... + * @returns string ... + */ +function basename(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return ''; + } + + // + const result = Path.basename(path); + return result; +} + +/** + * join several path segments together ... + * + * @param {...string} path path params ... + * @returns a joined paths ... + */ +function joinPath(...path) { + return Path.join(...path); +} + +/** + * resolve a relative path to absolute ... + * + * @param {string[]} path a path value to check ... + * @returns {string} + */ +function resolvePath(...path) { + return Path.resolve(...path); +} +//#endregion + +// +//#region File ... +/** + * determines a path destination is a file or not ... + * + * @param {string} path a path value to check ... + * @returns a boolean value ... + */ +function isFileExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + return stat.isFile(); + } catch { + return false; + } +} + +/** + * remove a file ... + * + * @param {string} path a file path ... + * @returns {Promise} action done or not ... + */ +function removeFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(false); + } + + // + fs.unlink(path, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * copy a file to destination path ... + * + * @param {string} source source file path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +function copyFile( + source = '', + dest = '' +) { + return new Promise((resolve) => { + // + if ( + !isFileExists(source) || + !isDirectoryExists(dest) + ) { + resolve(false); + return; + } + + // + const destFilePath = Path.join(dest, Path.basename(source)); + fs.copyFile(source, destFilePath, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * reading specified file content ... + * + * @param {string} path a file path ... + * @returns {Promise} file content ... + */ +function readFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(''); + return; + } + + // + fs.readFile(path, 'utf8', (err, content) => { + // + if (err) { + resolve(undefined); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * write content to a file ... + * + * @param {string} path a file path ... + * @param {string} content the content which going to write to the file ... + * @param {bool} overwrite determines file overwrite if exists ... + * @returns {Promise} action done or not ... + */ +function writeFile( + path = '', + content = '', + overwrite = true +) { + return new Promise((resolve) => { + // + if (isFileExists(path) && !overwrite) { + // + resolve(false); + return; + } + + // + // Normalize Content ... + content = XValueTools.isValidArg(content) ? + content : + ''; + + // + fs.writeFile(path, content, (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * create a file ... + * + * @param {string} path file path ... + * @param {string} fileName file name ... + * @returns {Promise} action done or not ... + */ +function createFile( + path = '', + fileName = '' +) { + return new Promise((resolve) => { + // + const filePath = Path.join(path, fileName); + if ( + isFileExists(filePath) || + !XValueTools.isValidArg(path) || + !XValueTools.isValidArg(fileName) + ) { + // + resolve(false); + return; + } + + // + fs.writeFile(filePath, '', (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * remove a file name extension ... + * + * @param {string} name + * @returns {string} name without extension ... + */ +function removeFileExtension(name = '') { + return name.substring(0, name.lastIndexOf('.')) || name; +} + +/** + * retrieve a file extension ... + * + * @param {string} path a path which locate a file ... + * @returns {string} + */ +function getFileExtension(path = '') { + // + let result = ""; + + // + // Validate Arg ... + if ( + !XValueTools.isValidArg(path) + || !isFileExists(path) + ) { + return result; + } + + // + // Retrieve just file name ... + const fileName = basename(path); + result = fileName.replace( + removeFileExtension(fileName), + "" + ); + + // + return result; +} + +/** + * retrieve all files list recursively from specific path ... + * + * @param {string} path a source folder path ... + * @param {string[]} extensions which file extensions need to be listed, live empty for all files ... + * @returns {Promise} + */ +async function getRecursiveFilesList( + path = "", + extensions = [] +) { + // + let result = []; + + // + // Validate Args ... + if ( + !XValueTools.isValidArg(path) + || !isDirectoryExists(path) + ) { + return result; + } + + // + const contents = await getDirectoryContents(path); + for (const item of contents) { + // + const itemPath = joinPath( + path, + item + ); + + // + const isItemFile = isFileExists(itemPath); + if (isItemFile) { + // + const itemFileExtension = getFileExtension(itemPath); + const isFileInSupportedExtensions = + extensions === undefined || extensions.length === 0 + ? true + : extensions.includes(itemFileExtension) + ; + if (isFileInSupportedExtensions) { + result.push(itemPath); + } + } else if (isDirectoryExists(itemPath)) { + // + const itemPathFiles = await getRecursiveFilesList(itemPath, extensions); + result.push(...itemPathFiles); + } + } + + // + return result; +} + +/** + * Extract Specific files from a folder and it's content ... + * + * @param {string} path Folder Path ... + * @returns + */ +async function extractFiles(path = "", ext = [], excludeWorkspaceFolders = []) { + // + const result = []; + + // + if (!ext || ext.length == 0) { + return result; + } + + // + const pathContent = await getDirectoryContents(path); + if (!pathContent || pathContent.length == 0) { + return result; + } + + // + // Loop through Content ... + for (const c of pathContent) { + // + // Prepare full path ... + const cPath = joinPath(path, c); + + // + // check content path is file or not ... + const isCFile = isFileExists(cPath); + const isCDirectory = isDirectoryExists(cPath); + if (isCFile) { + // + // Check it is MQL file or not ... + const cExt = getFileExtension(cPath); + if (ext.includes(cExt)) { + result.push(cPath); + } + } else if (isCDirectory) { + // + const destFolderName = basename(cPath); + const isExcluded = excludeWorkspaceFolders.includes(destFolderName); + if (isExcluded) { + continue; + } + + // + const cFiles = await extractFiles(cPath, ext); + if (cFiles && cFiles.length > 0) { + result.push(...cFiles); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Directory ... +/** + * create a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive create directories recursively ... + * @returns action done or not ... + */ +function createDirectory( + path = '', + recursive = true +) { + // + let result = false; + + // + if ( + isDirectoryExists(path) || + !XValueTools.isValidArg(path) + ) { + return false; + } + + // + try { + // + fs.mkdirSync(path, { recursive: recursive }); + result = true; + return result; + } catch { + return false; + } +} + +/** + * remove a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive removes directories recursively ... + * @returns {Promise} action done or not ... + */ +function removeDirectory( + path = '', + recursive = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve(false); + return; + } + + // + fs.rm(path, { + recursive + }, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * determines a path destination is a directory or not ... + * + * @param {string} path a folder path ... + * @returns represent destnation path is Directory or not ... + */ +function isDirectoryExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + // + const isExists = fs.existsSync(path); + if (!isExists) { + return false; + } + + // + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + const result = stat.isDirectory(); + return result; + } catch { + return false; + } +} + +/** + * retrieve a directory content ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryContents(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * retrieve a directory files ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryFiles( + path = '', + containsHiddenFiles = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + if (!containsHiddenFiles) { + content = content.filter(c => !c.startsWith('.')); + } + + // + const result = []; + content + .forEach(c => { + // + const cPath = Path.join(path, c); + if (isFileExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * retrieve a directory folders ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder names ... + */ +function getDirectoryFolders(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + const result = []; + content.forEach(c => { + // + const cPath = Path.join(path, c); + if (isDirectoryExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * copy a folder with all of it's content to dest ... + * + * @param {string} source source folder path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +async function copyFolder( + source = '', + dest = '' +) { + // + if ( + !isDirectoryExists(source) || + !XValueTools.isValidArg(dest) || + !XValueTools.isValidArg(source) + ) { + return false; + } + + // + const folderName = Path.basename(source); + const destPath = Path.join(dest, folderName); + + // + // Create Dest Path folder if not exists ... + if (!isDirectoryExists(destPath)) { + // + let result = createDirectory(destPath, true); + if (!result) { + return false; + } + } + + // + // Files ... + const files = await getDirectoryFiles(source); + if (files && files.constructor === Array && files.length > 0) { + // + const filesPromises = files.map(file => copyFile(Path.join(source, file), destPath)); + const filesResult = (await Promise.all(filesPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + // Folders ... + const folders = await getDirectoryFolders(source); + if (folders && folders.constructor === Array && folders.length > 0) { + // + const folderPromises = folders.map(folder => copyFolder(Path.join(source, folder), destPath)); + const filesResult = (await Promise.all(folderPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + return true; +} +//#endregion + +// +//#region Downloader ... +/** + * download a file from specific url and store it ... + * + * @param {string} filepath the file name and path which required to put download file on it ... + * @param {string} url the web url for downloading ... + */ +function download(filepath, url) { + // + // Validate Args ... + if ( + !XValueTools.isValidArg(url) + || !XValueTools.isValidURL(url) + || !XValueTools.isValidArg(filepath) + ) { + return; + } + + // + var file = fs.createWriteStream(filepath); + + // + if (url.startsWith('https:')) { + https.get(url, function (response) { + response.pipe(file); + }); + } else if (url.startsWith('http:')) { + http.get(url, function (response) { + response.pipe(file); + }); + } +} +//#endregion + +// +//#region JSON ... +/** + * read and parse a JSON content from a file ... + * + * @param {string} path source file path ... + * @returns {any} + */ +function readJSON(path = "") { + // + // Validate Args ... + if (!isFileExists(path)) { + return undefined; + } + + // + let result = undefined; + try { + result = require(path); + } catch { + result = undefined; + } + + // + return result; +} + +/** + * write a JSON Object content into a file ... + * + * @param {string} path dest file path ... + * @param {any} content an object which required to write to file ... + * @returns {Promise} + */ +async function writeJSON( + path = "", + content = undefined +) { + // + let result = false; + + // + // Validate Args ... + if (!XValueTools.isValidArg(path)) { + return result; + } + + // + // Normallize Content ... + if (content === undefined) { + content = {}; + } + + // + const contentString = XValueTools.beautifyJSON(content); + + // + result = await writeFile( + path, + contentString, + true + ); + + // + return result; +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + CurrentDir, + PathSeparator, + + // + getStatus, + getHomePath, + + // + basename, + joinPath, + resolvePath, + + // + download, + + // + readJSON, + writeJSON, + + // + copyFile, + readFile, + writeFile, + createFile, + removeFile, + isFileExists, + getFileExtension, + removeFileExtension, + getRecursiveFilesList, + extractFiles, + + // + copyFolder, + createDirectory, + removeDirectory, + isDirectoryExists, + getDirectoryFiles, + getDirectoryFolders, + getDirectoryContents, +}; +//#endregion \ No newline at end of file diff --git a/BKPS/14031218/Documents/JsModules/x-shell.tools.js b/BKPS/14031218/Documents/JsModules/x-shell.tools.js new file mode 100644 index 0000000..0ee13de --- /dev/null +++ b/BKPS/14031218/Documents/JsModules/x-shell.tools.js @@ -0,0 +1,219 @@ +/** + * XShell Tools Module ... + * a module for handling shell actions and retrieve OS Info in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const os = require('os'); +const process = require('process'); +const { exec } = require("child_process"); +const XFileTools = require('./x-file.tools'); +//#endregion + +// +//#region Constants ... +// +const OS = { + Aix: 'aix', + Darwin: 'darwin', + FreeBSD: 'freebsd', + Linux: 'linux', + OpenBSD: 'openbsd', + SnOS: 'sunos', + Windows: 'win32' +}; + +// +const isWindows = process.platform === OS.Windows; +//#endregion + +// +//#region Actions ... +// +//#region Pure shell commands ... +/** + * execute a command using NodeJS on shell ... + * + * @param {string} cmd command to execute ... + * @param {string} cwd working directory ... + * + * @returns Promise instance ... + */ +function execute(cmd, cwd) { + return new Promise((resolve, reject) => { + // + if (!cmd || cmd.toString().length === 0 || (cwd && !XFileTools.isDirectoryExists(cwd))) { + reject('invalid args ...'); + return; + } + + // + exec(cmd, { cwd }, (err, result, stdError) => { + // + if (err) { + reject(err); + return; + } + + // + if (stdError) { + // + // reject(stdError); + // return; + } + + // + resolve(result); + }); + }); +}; + +/** + * determines a command exists on host or not ... + * + * @param {string} name specific command name ... + * + * @returns boolean Promise ... + */ +function checkCommandExists(name) { + return new Promise(resolve => { + // + if (!name) { + resolve(false); + return; + } + + // + const cmd = isWindows ? `${name} >nul 2>&1` : `type ${name} >/dev/null 2>&1`; + execute(cmd).then(result => { + resolve(true); + }) + .catch(err => { + resolve(false); + }); + }); +} +//#endregion + +// +//#region required commands state ... +/** + * check al required commands exists or not ... + * + * @returns + */ +async function isRequiredCommandsExists() { + // + let result = false; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result = isNpmExists + && isNgExists + && isIonicExists + && isCordovaExists + ; + + // + return result; +} + +/** + * retrieve required commands state object ... + * + * @returns + */ +async function getRequiredCommandsStates() { + // + const result = {}; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result['npm'] = isNpmExists; + result['ng'] = isNgExists; + result['ionic'] = isIonicExists; + result['cordova'] = isCordovaExists; + + // + return result; +} +//#endregion + +// +//#region Commonly used Command Checkers ... +/** + * determines npm command exists or not ... + * + * @returns + */ +function isNpmCommandExists() { + return checkCommandExists('npm'); +} + +/** + * determines ng command exists or not ... + * + * @returns + */ +function isNgCommandExists() { + return checkCommandExists('ng'); +} + +/** + * determines ionic command exists or not ... + * + * @returns + */ +function isIonicCommandExists() { + return checkCommandExists('ionic'); +} + +/** + * determines cordova command exists or not ... + * + * @returns + */ +function isCordovaCommandExists() { + return checkCommandExists('cordova'); +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + execute, + checkCommandExists, + isRequiredCommandsExists, + getRequiredCommandsStates, + + // + isNgCommandExists, + isIonicCommandExists, + isCordovaCommandExists, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031218/Documents/JsModules/x-type-detector.tools.js b/BKPS/14031218/Documents/JsModules/x-type-detector.tools.js new file mode 100644 index 0000000..86ed3d8 --- /dev/null +++ b/BKPS/14031218/Documents/JsModules/x-type-detector.tools.js @@ -0,0 +1,268 @@ +/** + * DataType Tools Module ... + * a module for manipulate and detect supported data types in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Constants ... +/** + * all supported data types ... + */ +const DataTypes = { + Null: 'null', + Date: 'date', + Array: 'array', + Object: 'object', + String: 'string', + Number: 'number', + Unknown: 'unknown', + Boolean: 'boolean', + Function: 'function', + Undefined: 'undefined', +}; +//#endregion + +// +//#region Actions ... +/** + * detect type of a content ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getType(value) { + // + const type = typeof value; + + // + let result = DataTypes.Unknown; + let dateIdentifier = '[object Date]'; + let constructor = value && value.constructor ? + value.constructor.toString() : + ''; + + // + switch (type) { + // + case 'undefined': + result = DataTypes.Undefined; + break; + + // + case 'boolean': + result = DataTypes.Boolean; + break; + + // + case 'string': + result = DataTypes.String; + break; + + // + case 'number': + result = DataTypes.Number; + break; + + // + case 'function': + result = DataTypes.Function; + break; + + // + case 'object': + // + // Null ... + if (value === null) { + result = DataTypes.Null; + } else + // + // Array ... + if (Array.isArray(value)) { + result = DataTypes.Array; + } else + // + // Data ... + if ( + value instanceof Date || + isFunction(value.getMonth) || + constructor.includes(dateIdentifier) || + Object.prototype.toString.call(value) === dateIdentifier + ) { + result = DataTypes.Date; + } else + // + // Object ... + { + result = DataTypes.Object; + } + break; + + // + default: + result = DataTypes.Unknown; + break; + } + + // + return result; +} + +/** + * retrieve an object constructor ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getConstructor(value) { + // + const result = value && value.constructor ? + value.constructor.toString() : + ''; + + // + return result; +} + +/** + * retrieve an object prototype ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getPrototype(value) { + // + const result = value ? + Object.prototype.toString.call(value) : + ''; + + // + return result; +} + +/** + * check an object is null or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNull(value) { + return getType(value) === DataTypes.Null; +} + +/** + * check an object is undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isUndefined(value) { + return getType(value) === DataTypes.Undefined; +} + +/** + * check an object is null or undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNullOrUndefined(value) { + return isNull(value) || isUndefined(value); +} + +/** + * check an object is a date or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isDate(value) { + return getType(value) === DataTypes.Date; +} + +/** + * check an object is number or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNumber(value) { + return getType(value) === DataTypes.Number; +} + +/** + * check an object is string or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isString(value) { + return getType(value) === DataTypes.String; +} + +/** + * check an object is boolean or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isBoolean(value) { + return getType(value) === DataTypes.Boolean; +} + +/** + * check an object is an Array or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isArray(value) { + return getType(value) === DataTypes.Array; +} + +/** + * check an object is and Object or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isObject(value) { + return getType(value) === DataTypes.Object; +} + +/** + * check an object is a Function or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isFunction(value) { + return getType(value) === DataTypes.Function; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + DataTypes, + + // + getType, + getConstructor, + getPrototype, + isNull, + isUndefined, + isNullOrUndefined, + isDate, + isNumber, + isString, + isBoolean, + isArray, + isObject, + isFunction, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031218/Documents/JsModules/x-value.tools.js b/BKPS/14031218/Documents/JsModules/x-value.tools.js new file mode 100644 index 0000000..81cfcc4 --- /dev/null +++ b/BKPS/14031218/Documents/JsModules/x-value.tools.js @@ -0,0 +1,1528 @@ +/** + * Value Tools Module ... + * a module for Validate args and values ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const XTypeTools = require('./x-type-detector.tools'); +//#endregion + +// +//#region Actions ... +/** +* validate a value as an argument ... +* +* @param {string} value the value which going to validate ... +* @returns +*/ +function isValidArg(value) { + // + let result = false; + + // + result = value && + value.length > 0; + + // + return result; +} + +/** + * validate a collection of valuea as an arguments ... + * + * @param {string|string[]} values the value collection which going to checked ... + * @returns + */ +function isValidArgs(values) { + // + // Normalize Values ... + const normalValues = toNormalArray(values); + if (!hasChildArray(normalValues)) { + return false; + } + + // + let result = normalValues.every(nv => isValidArg(nv)); + return result; +} + +/** + * converts content to an array object ... + * + * @param {string|string[]} content the content which required to normalized ... + * @returns {string[]} array object ... + */ +function toNormalArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + const result = Array.isArray(content) ? + [...content] : + content.includes(',') && + content !== ',' ? + [...content.split(',')] : + [content]; + + // + return result; +} + +/** + * determines value is array and has atleast one child ... + * + * @param {any} value the value which going to checked ... + * @returns {boolean} result of checking ... + */ +function hasChildArray(value) { + // + let result = false; + result = value && + Array.isArray(value) && + value.length > 0; + + // + return result; +} + +/** + * check an string is ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} value specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function endsWidth( + symbol = '', + value = '', + ignoreCase = true +) { + // + if (!isValidArg(value)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + // TODO: uncomment it if necessary ... + // symbol = symbol.trim(); + + // + let result = false; + const subtractedContent = value.substring(value.length - symbol.length); + result = !!ignoreCase ? + subtractedContent + .toLowerCase() === symbol + .toLowerCase() : + subtractedContent === symbol; + + // + return result; +} + +/** + * surround specified content by provided symbol ... + * + * @param {string} symbol surround string ... + * @param {string} content used content to surrounded by symbol ... + * @returns surrounded content ... + */ +function surroundBy( + symbol = '', + content = '' +) { + // + // Validate Args ... + if (!isValidArg(content)) { + content = ''; + } + + // + if (!isValidArg(symbol)) { + symbol = ''; + } + + // + if (isSurrounded(symbol, content)) { + return content; + } + + // + const result = `${symbol}${content}${symbol}`; + return result; +} + +/** + * convert a parsed sign to clear string ... + * + * @param {string} value a parsed content ... + * @returns clear parsed signs ... + */ +function toStringExpression(value) { + // + let result = ''; + result = value; + + // + if ( + !value || + !isValidArg(value) || + !isSurroundedString(value) + ) { + return result; + } + + // + const startSymbol = value.charAt(0); + const endSymbol = value.charAt(value.length - 1); + + // + if (startSymbol !== endSymbol) { + return result; + } + + // + if ( + startSymbol === "\"" || + startSymbol === "\'" + ) { + result = clearSurround(startSymbol, value); + } + + // + return result; +} + + + +/** + * find and cleare proposed candidates from specified content ... + * + * @param {string|string[]} candidates the proposed string(s) whic going to cleared from content ... + * @param {string} content the destination content which used to find and replace candidates on it ... + * @returns cleared content ... + */ +function clearContent( + candidates, + content +) { + // + // Validate Args ... + if ( + !candidates || + !isValidArg(content) + ) { + return ''; + } + + // + // Normalize candidates ... + const normalCandidates = toNormalArray(candidates) + .filter(c => isValidArg(c)); + if (!hasChildArray(normalCandidates)) { + return content; + } + + // + // define regexp for content ... + const regExpExpression = normalCandidates.join('|'); + const regExp = new RegExp( + regExpExpression, + 'gi' + ); + + // + let result = ''; + result = content.replace(regExp, ''); + + // + return result; +} + +/** + * clear surrounded symbol from content ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified content to clear ... + * @returns + */ +function clearSurround( + symbol = '', + content = '' +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + (isValidArg(symbol) && + symbol.length >= content.length - 1) + ) { + return ''; + } + + // + // Validate Surround ... + if (!isSurrounded(symbol, content)) { + return content; + } + + // + if (!isValidArg(symbol)) { + return content; + } + + // + let result = content.substring(symbol.length, content.length - symbol.length); + return result; +} + +/** + * clear object sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearObjectSurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedObject(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth('}', content) ? + 1 : + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * clear array sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearArraySurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedArray(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth(']', content) ? + 1 : + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * slice a content to individual parts ... + * + * @param {number|number[]} indexes which indexes used to slice ... + * @param {strng} content the content which going to sliced ... + * @returns sliced parts of content ... + */ +function sliceContent(indexes, content) { + // + // Validate Args ... + if ( + !isValidArg(indexes) || + !isValidArg(content) + ) { + return []; + } + + // + // Normalize indexes ... + const normalIndexes = toNormalArray(indexes) + .filter(index => index > -1 && index < content.length); + if (!hasChildArray(normalIndexes)) { + return []; + } + + // + let result = ['']; + result.pop(); + + // + let lastIndex = 0; + for (const index of normalIndexes) { + // + const part = content.substring(lastIndex, index); + if (isValidArg(part)) { + result.push(part.trim()); + } + + // + lastIndex = index + 1; + } + + // + // check remained parts ... + if (lastIndex < content.length) { + // + const part = content.substring(lastIndex); + if (isValidArg(part)) { + result.push(part.trim()); + } + } + + // + return result; +} + + + +/** + * check an string is starts and ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function isSurrounded( + symbol = '', + content = '', + ignoreCase = true +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + symbol = symbol.trim(); + + // + let result = false; + result = (!!ignoreCase ? + content + .toLowerCase() + .startsWith(symbol.toLowerCase()) : + content.startsWith(symbol) + ) && + endsWidth(symbol, content, ignoreCase); + + // + return result; +} + +/** + * determines a content is an string surrounded value or not ... + * + * @param {string} content a content which going to check ... + * @returns + */ +function isSurroundedString(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = ( + content.startsWith('\'') && + ( + endsWidth('\'', content) || + endsWidth('\',', content) || + endsWidth('\';', content) || + endsWidth('\'\n', content) + ) || + content.startsWith('\"') && + ( + endsWidth('\"', content) || + endsWidth('\",', content) || + endsWidth('\";', content) || + endsWidth('\"\n', content) + ) || + content.startsWith('`') && + ( + endsWidth('\`', content) || + endsWidth('\`,', content) || + endsWidth('\`;', content) || + endsWidth('\`\n', content) + ) + ); + return result; +} + +/** + * check a content is an array content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('[') && + ( + endsWidth(']', content) || + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) + ); + return result; +} + +/** + * check a content is an object content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedObject(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('{') && + ( + endsWidth('}', content) || + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) + ); + return result; +} + +/** + * check an index model is contains inside anothers or not ... + * + * @param {{ start: number, end: number}} source the source index model to check ... + * @param {...{ start: number, end: number}} dest the collection of index models which going to check ... + * @returns + */ +function isIndexInside(source, ...dest) { + // + let result = false; + + // + // Validate Args ... + if (!source || !dest) { + return result; + } + + // + // Check idx is standard ... + if ( + !source || + !source.end || + !source.start || + source.start > source.end + ) { + return false; + } + + // + // Check types of destinations ... + for (let index of dest) { + // + // Check idx is standard ... + if ( + !index || + !index.end || + !index.start || + index.start > index.end + ) { + return false; + } + } + + // + if (dest.includes(source)) { + dest = dest.filter(d => d !== source); + } + + // + const insideContentIndex = dest.find(dIndex => { + // + const result = source.start >= dIndex.start && + source.start <= dIndex.end && + source.end >= dIndex.start && + source.end <= dIndex.end; + return result; + }); + + // + result = insideContentIndex; + return result; +} + +/** + * check a number exists in + * @param {number} idx the number which going to check ... + * @param {{ start: number, end: number}} index the index model + * @returns + */ +function isInsideIndex(idx = -1, index) { + // + let result = false; + + // + // Validate Args ... + if ( + !index || + !index.hasOwnProperty('end') || + !index.hasOwnProperty('start') + ) { + return result; + } + + // + result = idx > index.start && idx < index.end; + return result; +} + +/** + * determines an object is key/value and type ... + * + * @param {any} content the object which we are going to check ... + * @returns + */ +function isKeyValueType(content) { + // + const result = content && + content.hasOwnProperty('key') && + content.hasOwnProperty('type') && + content.hasOwnProperty('value'); + + // + return result; +} + + + +/** + * find all indexes of token(s) in content ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns {number[]} all occured indexes ... + */ +function findAllIndexes( + tokens, + content +) { + // + // Validate Args ... + if ( + !isValidArg(tokens) || + !isValidArg(content) + ) { + return []; + } + + // + // normalize tokens ... + const normalTokens = toNormalArray(tokens); + if (!hasChildArray(normalTokens)) { + return []; + } + + // + // Parse contents ... + let match; + const result = []; + const regExp = new RegExp( + normalTokens.join('|'), + 'g' + ); + while ((match = regExp.exec(content)) !== null) { + result.push(match.index); + } + if (!hasChildArray(result)) { + return []; + } + + // + return result; +} + +/** + * find nearest symbol in a content from specified index ... + * + * @param {string|string[]} candidates specifies which symbols to find ... + * @param {string} content te content for seasrch ... + * @param {number} startFromIndex the index of start position ... + * @returns + */ +function findNearest( + candidates, + content = '', + startFromIndex = 0 +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) || + !isValidArg(content.trim()) + ) { + return ''; + } + + // + // Normalize Content ... + content = content.trim(); + + // + // Normalize Starts From ... + startFromIndex = startFromIndex < 0 || startFromIndex > content.length - 1 ? 0 : startFromIndex; + + // + // Normalize Symbols ... + const normalCandidates = toNormalArray(candidates); + if (!hasChildArray(normalCandidates)) { + return ''; + } + + // + let nearestIndex = findNearestIndex( + normalCandidates, + content, + startFromIndex + ); + if (nearestIndex < 0) { + return ''; + } + + // + let result = content.substring( + nearestIndex, + nearestIndex + Math.max(...normalCandidates.map(nc => nc.length)) + ).trim(); + return result; +} + +/** + * search candidates in content and find nearest one and return it ... + * + * @param {string|string[]} candidates which candidates required to check ... + * @param {string} content the content which required to search candidates ... + * @param {number} startFromIndex the proposed index to start searching content from on ... + * @returns + */ +function findNearestIndex( + candidates = [''], + content = '', + startFromIndex = 0, + ignoreClosedItems = false +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) + ) { + return -1; + } + + // + // Mormalize startFromIndex value ... + startFromIndex = startFromIndex < 0 ? + 0 : + startFromIndex > content.length - 1 ? + content.length - 1 : + startFromIndex; + + // + // Normalize candidates ... + let normalCandidates = toNormalArray(candidates); + + // + if (!!ignoreClosedItems) { + normalCandidates = normalCandidates + .map(c => content.indexOf( + c, + startFromIndex + ) + ).map(c => +c) + .filter(c => +c > -1); + } else { + normalCandidates = findAllIndexesOutOfCloseds(normalCandidates, content) + .filter(c => c >= startFromIndex); + } + if (!hasChildArray(normalCandidates)) { + return -1; + } + + // + let result = -1; + result = Math.min(...normalCandidates); + + // + return result; +} + +/** + * find close index of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findCloseIndex( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = -1 +) { + // + // Validate Args ... + if ( + startsFrom < 0 || + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + openSymbol === closeSymbol || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + startsFrom > content.length - 1 + ) { + return -1; + } + + // + let result = -1; + + // + let index = startsFrom; + const openSignStack = []; + while (index < content.length) { + // + const openCandidate = content.substring(index, index + openSymbol.length); + const closeCandidate = content.substring(index, index + closeSymbol.length); + + // + if (openCandidate === openSymbol) { + openSignStack.push(index); + } else if (closeCandidate === closeSymbol) { + // + if (openSignStack.length > 0) { + openSignStack.pop(); + } + + // + if (openSignStack.length === 0) { + result = index; + break; + } + } + + // + index++; + } + + // + return result; +} + +/** + * find closed contents of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findClosedContent( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = 0, +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + openSymbol.length >= content.length || + closeSymbol.length >= content.length + ) { + return result; + } + + // + // Normalize Start From ... + startsFrom = startsFrom < 0 || startsFrom >= content.length ? 0 : startsFrom; + + // + let canContinue = true; + while (!!canContinue) { + // + let openSymbolIndex = content.indexOf(openSymbol, startsFrom); + if (openSymbolIndex < 0) { + // + canContinue = false; + continue; + } + + // + let closeSymbolIndex = findCloseIndex( + openSymbol, + closeSymbol, + content, + openSymbolIndex + ); + if (closeSymbolIndex < 0) { + // + canContinue = false; + continue; + } + if (content.charAt(closeSymbolIndex) !== closeSymbol) { + closeSymbolIndex++; + } + + // + // Prevent ${} string interpolations ... + if ( + openSymbol === '{' && + openSymbolIndex - 1 >= 0 + ) { + // + const prevChar = content.charAt(openSymbolIndex - 1); + if (prevChar === '$') { + continue; + } + } + + // + const item = content + .substring(openSymbolIndex, closeSymbolIndex + 1) + .trim(); + startsFrom = closeSymbolIndex + 1; + result.push({ + start: openSymbolIndex, + end: closeSymbolIndex, + content: item + }); + } + + // + if (!hasChildArray(result)) { + return result; + } + + // + return result; +} + +/** + * extract a collection of closed contents exists in a content ... + * + * @param symbols a collection of open and close contents ... + * @param {string} content a content for searching inside it ... + * @returns a collection of closed content ... + */ +function findClosedContents( + symbols = [ + { + openSymbol: '', + closeSymbol: '' + } + ], + content = '' +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + if ( + !isValidArg(content) || + !hasChildArray(symbols) + ) { + return []; + } + + // + symbols.forEach(symbol => { + // + const closedContent = findClosedContent( + symbol.openSymbol, + symbol.closeSymbol, + content + ); + + // + if (hasChildArray(closedContent)) { + result.push( + ...closedContent + ); + } + }); + + // + return result; +} + +/** + * find all string content closed items ... + * + * @param {string} content a content which going to search ... + * @returns a collection of index descriptors ... + */ +function findClosedStrings(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // there are 3 types of strings ... + // ' " and ` + + // + const token1 = '\''; + const token1Stack = [0]; + token1Stack.pop(); + + // + const token2 = '"'; + const token2Stack = [0]; + token2Stack.pop(); + + // + const token3 = '`'; + const token3Stack = [0]; + token3Stack.pop(); + + // + const result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + for (let i = 0; i < content.length; i++) { + // + const currentChart = content.charAt(i); + + // + //#region Token 1 ... + if (currentChart === token1) { + // + if (!hasChildArray(token1Stack)) { + token1Stack.push(i); + } else { + // + const start = token1Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 2 ... + if (currentChart === token2) { + // + if (!hasChildArray(token2Stack)) { + token2Stack.push(i); + } else { + // + const start = token2Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 3 ... + if (currentChart === token3) { + // + if (!hasChildArray(token3Stack)) { + token3Stack.push(i); + } else { + // + const start = token3Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + } + + // + return result; +} + +/** + * find container indexes from within indexes ... + * + * @param {...{start: number, end: number}} index the collection of indexes to find beiggers inside ... + * @returns + */ +function findContainerIndexes(...index) { + // + let result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + let concatedIndexes = []; + for (let idx of index) { + // + // Index Childs ... + for (let iix of idx) { + // + // Check idx is standard ... + if ( + !iix || + !iix.end || + !iix.start || + iix.start > iix.end + ) { + continue; + } + + // + // Check index inside another index ... + concatedIndexes.push(iix); + } + } + + // + if (!hasChildArray(concatedIndexes)) { + return result; + } + + // + for (let ccIdx of concatedIndexes) { + // + const isInside = isIndexInside(ccIdx, ...concatedIndexes); + if (isInside) { + continue; + } + + // + if (hasChildArray(result)) { + // + const isInsideResult = isIndexInside(ccIdx, ...result); + if (isInsideResult) { + continue; + } + } + + // + result.push(ccIdx); + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds1( + tokens, + content, +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Extract token Indexes ... + const tokensIndexes = findAllIndexes(tokens, content); + if (!hasChildArray(tokensIndexes)) { + return []; + } + + // + // Extract Closed Objects Indexes ... + const closedArrays = findClosedContent('[', ']', content); + const closedObjects = findClosedContent('{', '}', content); + const closedStrings = findClosedStrings(content); + if ( + !hasChildArray(closedObjects) && + !hasChildArray(closedArrays) && + !hasChildArray(closedStrings) + ) { + return tokensIndexes; + } + + // + // find bigger sloded ... + let containerClosedItems = findContainerIndexes( + closedArrays, + closedObjects, + closedStrings + ).filter(i => !isSurroundedString(i.content)); + + // + let result = [-1]; + result.pop(); + + // + for (let tIdx of tokensIndexes) { + // + let canAdd = true; + for (let ccIndex of containerClosedItems) { + // + canAdd = isInsideIndex(tIdx, ccIndex); + if (canAdd) { + break; + } + } + + // + if (!canAdd) { + result.push(tIdx); + } + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds( + tokens, + content, +) { + // + // Define Result ... + let result = [-1]; + result.pop(); + + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Normalize Tokens ... + const normalizeTokens = toNormalArray(tokens); + if (!hasChildArray(normalizeTokens)) { + return result; + } + + // + // Extract Closed Objects Indexes ... + let openSymbols = [ + '{', + '[', + '\'', + '"', + '`' + ]; + let closeSymbols = [ + '}', + ']', + '\'', + '"', + '`' + ]; + let openStack = []; + let lastOpenSymbol = ''; + let lastClosedIndex = -1; + for (let i = 0; i < content.length; i++) { + // + const prevChar = content.charAt(i - 1) || ''; + const char = content.charAt(i); + const nextChar = content.charAt(i + 1) || ''; + + // + const isToken = normalizeTokens.includes(char); + const isOpenSymbol = openSymbols.includes(char); + const isCloseSymbol = closeSymbols.includes(char); + + // + if (isOpenSymbol && lastOpenSymbol !== char) { + openStack.push(i); + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? char : lastOpenSymbol; + } else if (isCloseSymbol) { + // + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? '' : lastOpenSymbol; + let lastPop = openStack.pop(); + if (openStack.length === 0) { + lastClosedIndex = lastPop; + } + } else if (isToken) { + if ( + i > lastClosedIndex && + openStack.length === 0 + ) { + result.push(i); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Validator Actions ... +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + * @returns {boolean} + */ +function isValidURL(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + const pattern = new RegExp( + '^([a-zA-Z]+:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', // fragment locator + 'i' + ); + + // + const result = pattern.test(value); + return result; +} + +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + */ +function isValidEmail(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + // + const pattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gim; + + // + const result = pattern.test(value); + return result; +} +//#endregion + +// +//#region Normallizers ... +/** + * normallize an string ... + * + * @param {string} value specified value ... + * @returns {string} + */ +function toNormalString(value = "") { + // + if (!XTypeTools.isString(value)) { + value = ""; + } + + // + const result = value + .trim() + .toLowerCase(); + + // + return result; +} +//#endregion + +// +//#region Beautifiers ... +/** + * converts an object to string based on json and beautify result ... + * + * @param {any} object + * @returns {string} + */ +function beautifyJSON(object = undefined) { + // + // TODO: Complete this ... + let result = ""; + + // + // validate object ... + if (object === undefined) { + return result; + } + + // + // Convert result ... + result = JSON.stringify( + object, + null, + 4 + ); + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + endsWidth, + surroundBy, + isValidArg, + isValidArgs, + toNormalArray, + hasChildArray, + toStringExpression, + + // + sliceContent, + clearContent, + clearSurround, + clearArraySurround, + clearObjectSurround, + + // + isSurrounded, + isIndexInside, + isInsideIndex, + isKeyValueType, + isSurroundedArray, + isSurroundedString, + isSurroundedObject, + + // + findNearest, + findAllIndexes, + findCloseIndex, + findNearestIndex, + findClosedContent, + findClosedStrings, + findClosedContents, + findAllIndexesOutOfCloseds, + + // + // Validator Actions ... + isValidURL, + isValidEmail, + + // + // Normallizers ... + toNormalString, + + // + beautifyJSON, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031218/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 b/BKPS/14031218/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 new file mode 100644 index 0000000..ec3e257 --- /dev/null +++ b/BKPS/14031218/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 @@ -0,0 +1,542 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XEATemplate +// Description: a Template For Exper Advisors +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XEATemplate" +#property strict + +// +#define ShortName "XEATemplate" + +// +// Imports ... +#include "../Classes/x-saherelm.xalert.class.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = false; // Report New Days +input bool eaReportNewHours = false; // Report New Hours + +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XSCTrade *eaTrader; // Trader of Expert Adviser ... +XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... +XSCXCTHelper *eaCHelper; // Bar Timer Indicator Helper class ... +XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) { + return INIT_FAILED; + } + + // + // Initialize all Requirements ... + if (!InitEA()) + { + return INIT_FAILED; + } + + // + // Initialize all GUI Objects and Classes ... + if (!InitGUI()) + { + return INIT_FAILED; + } + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + DestroyTimer(); + + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + UpdateGUI(); + HandleReportTime(); + UpdatePositionsState(); + + // + // TODO: Implemetn Tick Processors Algorithm ... +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // TODO: Implement Time Based Functionalities ... +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + // + // Handle OnClick Event ... + if (id == CHARTEVENT_OBJECT_CLICK) + { + HandleOnClickEvent(sparam); + } +} + +// +// Custom Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + HandleReportBalance(); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() { + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() { + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initialize all Requirements for Working Fine ... + * + * @return ( bool ) + */ +bool InitEA() +{ + // + bool result = false; + + // + // Locally Apply Changes on Prefix ... + eaLogTag = ShortName + ">" + eaLogSuffix; + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + eaCHelper = new XSCXCTHelper(); + result = eaCHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + eaCCHelper = new XSCXCCHelper(); + result = eaCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Instance of Alert Class and Configure it ... + eaAlert = new XSCAlert(); + eaAlert.SetPrefix(eaLogTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance and Configure it ... + eaTrader = new XSCTrade( + eaSlippage, + eaMagicNumber // + ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + return result; +} + +/** + * Destroy all Initialized EA Requirements ... + */ +void DestroyEA() +{ + // + delete eaCHelper; + delete eaCCHelper; + + // + delete eaAlert; +} + +/** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ +bool InitGUI() +{ + // + bool result = false; + + // + // TODO: Fix This ... + result = true; + + // + return result; +} + +/** + * Update GUI based on Each Ticks ... + */ +void UpdateGUI() +{ + // + // TODO: Implement this ... +} + +/** + * Destroy all Initialized GUi Requirements ... + */ +void DestroyGUI() +{ + // + // TODO: Complete this ... +} + +// +// Others ... + +/** + * Update Positions States ... + */ +void UpdatePositionsState() +{ + // + // TODO: Implement this ... +} + +/** + * Handle On Click Event for GUI Components ... + * + * @param name: Object Name ... + */ +void HandleOnClickEvent(string name) +{ + // + if (!IsValid(name)) + { + return; + } + + // + bool isClicked = false; + + // + // TODO: Implement Chart Objects On Click ... + + // + if (isClicked) + { + UpdateGUI(); + } +} + +/** + * Report Account Balance ... + */ +void HandleReportBalance() +{ + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(eaTrader.mAccount.GetBalance()); + eaAlert.Log(msg); +} + +/** + * Time Reporting based on Inputs ... + */ +void HandleReportTime() +{ + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.Alert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.Alert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.Alert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.Alert(msg); + } +} + +// diff --git a/BKPS/14031218/Documents/Temlates/x-saherelm.x-panel.ea.mq5 b/BKPS/14031218/Documents/Temlates/x-saherelm.x-panel.ea.mq5 new file mode 100644 index 0000000..c04228d --- /dev/null +++ b/BKPS/14031218/Documents/Temlates/x-saherelm.x-panel.ea.mq5 @@ -0,0 +1,575 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XPanelEA +// Description: an Exper Advisor which used Panels +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XPanelEA" +#property strict + +// +#define ShortName "XPANELEA" + +// +// Imports ... +#include "../Classes/x-saherelm.x-app-dialog.class.mq5" +#include "../Classes/x-saherelm.xalert.class.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = false; // Report New Days +input bool eaReportNewHours = false; // Report New Hours + +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XSCTrade *eaTrader; // Trader of Expert Adviser ... +XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... +XSCXCTHelper *eaCTHelper; // Bar Timer Indicator Helper class ... +XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... + +// +XCAppDialog eaMainWindow; // EA Main Dialog ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Initialize all Requirements ... + if (!InitEA()) + { + return INIT_FAILED; + } + + // + // Initialize all GUI Objects and Classes ... + if (!InitGUI()) + { + return INIT_FAILED; + } + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + DestroyTimer(); + + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + UpdateGUI(); + HandleReportTime(); + UpdatePositionsState(); + + // + // TODO: Implemetn Tick Processors Algorithm ... +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // TODO: Implement Time Based Functionalities ... +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + // + // Apply Chart Event on Main Window ... + eaMainWindow.ChartEvent(id, lparam, dparam, sparam); + + // + // Handle OnClick Event ... + if (id == CHARTEVENT_OBJECT_CLICK) + { + HandleOnClickEvent(sparam); + } +} + +// +// Custom Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + HandleReportBalance(); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initialize all Requirements for Working Fine ... + * + * @return ( bool ) + */ +bool InitEA() +{ + // + bool result = false; + + // + // Locally Apply Changes on Prefix ... + eaLogTag = ShortName + ">" + eaLogSuffix; + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + eaCTHelper = new XSCXCTHelper(); + result = eaCTHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + eaCCHelper = new XSCXCCHelper(); + result = eaCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Instance of Alert Class and Configure it ... + eaAlert = new XSCAlert(); + eaAlert.SetPrefix(eaLogTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance and Configure it ... + eaTrader = new XSCTrade( + eaSlippage, + eaMagicNumber // + ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + return result; +} + +/** + * Destroy all Initialized EA Requirements ... + */ +void DestroyEA() +{ + // + delete eaCTHelper; + delete eaCCHelper; + + // + delete eaAlert; +} + +/** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ +bool InitGUI() +{ + // + bool result = false; + + // + // Initialize Application Main Window ... + result = eaMainWindow.Create( + ChartID(), + ShortName, // Dialog Name ... + 0, // SubWindow ... + 10, // X1 ... + 35, // Y1 ... + 300, // X2 ... + 200 // Y2 ... + ); + + // + // Configuring Dialog ... + // eaMainWindow.MinimizeButton(false); // Hide Minimize Button ... + // eaMainWindow.CloseButton(false); // Hide Close Button ... + eaMainWindow.BackgroundColor(clrBlack); + // result = true; + + // + // Try To Run Main Window ... + if (result) + { + eaMainWindow.Run(); + } + + // + return result; +} + +/** + * Update GUI based on Each Ticks ... + */ +void UpdateGUI() +{ + // + // TODO: Implement this ... +} + +/** + * Destroy all Initialized GUi Requirements ... + */ +void DestroyGUI() +{ + // + eaMainWindow.Destroy(); +} + +// +// Others ... + +/** + * Update Positions States ... + */ +void UpdatePositionsState() +{ + // + // TODO: Implement this ... +} + +/** + * Handle On Click Event for GUI Components ... + * + * @param name: Object Name ... + */ +void HandleOnClickEvent(string name) +{ + // + if (!IsValid(name)) + { + return; + } + + // + bool isClicked = false; + + // + // TODO: Implement Chart Objects On Click ... + + // + if (isClicked) + { + UpdateGUI(); + } +} + +/** + * Report Account Balance ... + */ +void HandleReportBalance() +{ + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(eaTrader.mAccount.GetBalance()); + eaAlert.Log(msg); +} + +/** + * Time Reporting based on Inputs ... + */ +void HandleReportTime() +{ + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.Alert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.Alert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.Alert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.Alert(msg); + } +} + +// diff --git a/BKPS/14031218/Experts/Advisors/ExpertMACD.mq5 b/BKPS/14031218/Experts/Advisors/ExpertMACD.mq5 new file mode 100644 index 0000000..0e4c57c --- /dev/null +++ b/BKPS/14031218/Experts/Advisors/ExpertMACD.mq5 @@ -0,0 +1,168 @@ +//+------------------------------------------------------------------+ +//| ExpertMACD.mq5 | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMACD"; +int Expert_MagicNumber =10981; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MACD_PeriodFast =12; +input int Inp_Signal_MACD_PeriodSlow =24; +input int Inp_Signal_MACD_PeriodSignal=9; +input int Inp_Signal_MACD_TakeProfit =50; +input int Inp_Signal_MACD_StopLoss =20; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMACD *signal=new CSignalMACD; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodFast(Inp_Signal_MACD_PeriodFast); + signal.PeriodSlow(Inp_Signal_MACD_PeriodSlow); + signal.PeriodSignal(Inp_Signal_MACD_PeriodSignal); + signal.TakeLevel(Inp_Signal_MACD_TakeProfit); + signal.StopLevel(Inp_Signal_MACD_StopLoss); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingNone *trailing=new CTrailingNone; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Advisors/ExpertMAMA.mq5 b/BKPS/14031218/Experts/Advisors/ExpertMAMA.mq5 new file mode 100644 index 0000000..68e8bb8 --- /dev/null +++ b/BKPS/14031218/Experts/Advisors/ExpertMAMA.mq5 @@ -0,0 +1,175 @@ +//+------------------------------------------------------------------+ +//| ExpertMAMA.mq5 | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAMA"; +int Expert_MagicNumber =12003; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input int Inp_Trailing_MA_Period =12; +input int Inp_Trailing_MA_Shift =0; +input ENUM_MA_METHOD Inp_Trailing_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Trailing_MA_Applied=PRICE_CLOSE; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingMA *trailing=new CTrailingMA; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Period(Inp_Trailing_MA_Period); + trailing.Shift(Inp_Trailing_MA_Shift); + trailing.Method(Inp_Trailing_MA_Method); + trailing.Applied(Inp_Trailing_MA_Applied); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Advisors/ExpertMAPSAR.mq5 b/BKPS/14031218/Experts/Advisors/ExpertMAPSAR.mq5 new file mode 100644 index 0000000..1eae701 --- /dev/null +++ b/BKPS/14031218/Experts/Advisors/ExpertMAPSAR.mq5 @@ -0,0 +1,171 @@ +//+------------------------------------------------------------------+ +//| ExpertMAPSAR.mq5 | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAPSAR"; +int Expert_MagicNumber =14598; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input double Inp_Trailing_ParabolicSAR_Step =0.02; +input double Inp_Trailing_ParabolicSAR_Maximum=0.2; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingPSAR *trailing=new CTrailingPSAR; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Step(Inp_Trailing_ParabolicSAR_Step); + trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 b/BKPS/14031218/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 new file mode 100644 index 0000000..e7da4e7 --- /dev/null +++ b/BKPS/14031218/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 @@ -0,0 +1,176 @@ +//+------------------------------------------------------------------+ +//| ExpertMAPSARSizeOptimized.mq5 | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAPSARSizeOptimized"; +int Expert_MagicNumber =27893; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input double Inp_Trailing_ParabolicSAR_Step =0.02; +input double Inp_Trailing_ParabolicSAR_Maximum =0.2; +//--- inputs for money +input double Inp_Money_SizeOptimized_DecreaseFactor=3.0; +input double Inp_Money_SizeOptimized_Percent =10.0; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingPSAR *trailing=new CTrailingPSAR; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Step(Inp_Trailing_ParabolicSAR_Step); + trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneySizeOptimized *money=new CMoneySizeOptimized; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters + money.DecreaseFactor(Inp_Money_SizeOptimized_DecreaseFactor); + money.Percent(Inp_Money_SizeOptimized_Percent); +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Examples/ChartInChart/ChartInChart.mq5 b/BKPS/14031218/Experts/Examples/ChartInChart/ChartInChart.mq5 new file mode 100644 index 0000000000000000000000000000000000000000..3ae10829b653b97ae370e06b0cf5ff9c7fcb8a13 GIT binary patch literal 30544 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 VIjM}W{H>X${Eth`3(jVa`hVyemIeR- literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Controls/Controls.mq5 b/BKPS/14031218/Experts/Examples/Controls/Controls.mq5 new file mode 100644 index 0000000..b10deb2 --- /dev/null +++ b/BKPS/14031218/Experts/Examples/Controls/Controls.mq5 @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| Controls.mq5 | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "ControlsDialog.mqh" +//+------------------------------------------------------------------+ +//| Global Variables | +//+------------------------------------------------------------------+ +CControlsDialog ExtDialog; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create application dialog + if(!ExtDialog.Create(0,"Controls",0,20,20,360,324)) + return(INIT_FAILED); +//--- run application + ExtDialog.Run(); +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy dialog + ExtDialog.Destroy(reason); + } +//+------------------------------------------------------------------+ +//| Expert chart event function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // event ID + const long& lparam, // event parameter of the long type + const double& dparam, // event parameter of the double type + const string& sparam) // event parameter of the string type + { + ExtDialog.ChartEvent(id,lparam,dparam,sparam); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Examples/Controls/ControlsDialog.mqh b/BKPS/14031218/Experts/Examples/Controls/ControlsDialog.mqh new file mode 100644 index 0000000..4ed57d7 --- /dev/null +++ b/BKPS/14031218/Experts/Examples/Controls/ControlsDialog.mqh @@ -0,0 +1,427 @@ +//+------------------------------------------------------------------+ +//| ControlsDialog.mqh | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +//--- indents and gaps +#define INDENT_LEFT (11) // indent from left (with allowance for border width) +#define INDENT_TOP (11) // indent from top (with allowance for border width) +#define INDENT_RIGHT (11) // indent from right (with allowance for border width) +#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width) +#define CONTROLS_GAP_X (5) // gap by X coordinate +#define CONTROLS_GAP_Y (5) // gap by Y coordinate +//--- for buttons +#define BUTTON_WIDTH (100) // size by X coordinate +#define BUTTON_HEIGHT (20) // size by Y coordinate +//--- for the indication area +#define EDIT_HEIGHT (20) // size by Y coordinate +//--- for group controls +#define GROUP_WIDTH (150) // size by X coordinate +#define LIST_HEIGHT (179) // size by Y coordinate +#define RADIO_HEIGHT (56) // size by Y coordinate +#define CHECK_HEIGHT (93) // size by Y coordinate +//+------------------------------------------------------------------+ +//| Class CControlsDialog | +//| Usage: main dialog of the Controls application | +//+------------------------------------------------------------------+ +class CControlsDialog : public CAppDialog + { +private: + CEdit m_edit; // the display field object + CButton m_button1; // the button object + CButton m_button2; // the button object + CButton m_button3; // the fixed button object + CSpinEdit m_spin_edit; // the up-down object + CDatePicker m_date; // the datepicker object + CListView m_list_view; // the list object + CComboBox m_combo_box; // the dropdown list object + CRadioGroup m_radio_group; // the radio buttons group object + CCheckGroup m_check_group; // the check box group object + +public: + CControlsDialog(void); + ~CControlsDialog(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + //--- create dependent controls + bool CreateEdit(void); + bool CreateButton1(void); + bool CreateButton2(void); + bool CreateButton3(void); + bool CreateSpinEdit(void); + bool CreateDate(void); + bool CreateListView(void); + bool CreateComboBox(void); + bool CreateRadioGroup(void); + bool CreateCheckGroup(void); + //--- handlers of the dependent controls events + void OnClickButton1(void); + void OnClickButton2(void); + void OnClickButton3(void); + void OnChangeSpinEdit(void); + void OnChangeDate(void); + void OnChangeListView(void); + void OnChangeComboBox(void); + void OnChangeRadioGroup(void); + void OnChangeCheckGroup(void); + }; +//+------------------------------------------------------------------+ +//| Event Handling | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CControlsDialog) + ON_EVENT(ON_CLICK,m_button1,OnClickButton1) + ON_EVENT(ON_CLICK,m_button2,OnClickButton2) + ON_EVENT(ON_CLICK,m_button3,OnClickButton3) + ON_EVENT(ON_CHANGE,m_spin_edit,OnChangeSpinEdit) + ON_EVENT(ON_CHANGE,m_date,OnChangeDate) + ON_EVENT(ON_CHANGE,m_list_view,OnChangeListView) + ON_EVENT(ON_CHANGE,m_combo_box,OnChangeComboBox) + ON_EVENT(ON_CHANGE,m_radio_group,OnChangeRadioGroup) + ON_EVENT(ON_CHANGE,m_check_group,OnChangeCheckGroup) +EVENT_MAP_END(CAppDialog) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CControlsDialog::CControlsDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CControlsDialog::~CControlsDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Create | +//+------------------------------------------------------------------+ +bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { + if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create dependent controls + if(!CreateEdit()) + return(false); + if(!CreateButton1()) + return(false); + if(!CreateButton2()) + return(false); + if(!CreateButton3()) + return(false); + if(!CreateSpinEdit()) + return(false); + if(!CreateListView()) + return(false); + if(!CreateDate()) + return(false); + if(!CreateRadioGroup()) + return(false); + if(!CreateCheckGroup()) + return(false); + if(!CreateComboBox()) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the display field | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateEdit(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP; + int x2=ClientAreaWidth()-INDENT_RIGHT; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_edit.ReadOnly(true)) + return(false); + if(!Add(m_edit)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button1" button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton1(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button1.Text("Button1")) + return(false); + if(!Add(m_button1)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button2" button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton2(void) + { +//--- coordinates + int x1=INDENT_LEFT+(BUTTON_WIDTH+CONTROLS_GAP_X); + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button2.Text("Button2")) + return(false); + if(!Add(m_button2)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button3" fixed button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton3(void) + { +//--- coordinates + int x1=INDENT_LEFT+2*(BUTTON_WIDTH+CONTROLS_GAP_X); + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button3.Create(m_chart_id,m_name+"Button3",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button3.Text("Locked")) + return(false); + if(!Add(m_button3)) + return(false); + m_button3.Locking(true); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "SpinEdit" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateSpinEdit(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_spin_edit.Create(m_chart_id,m_name+"SpinEdit",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_spin_edit)) + return(false); + m_spin_edit.MinValue(10); + m_spin_edit.MaxValue(1000); + m_spin_edit.Value(100); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "DatePicker" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateDate(void) + { +//--- coordinates + int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_date.Create(m_chart_id,m_name+"Date",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_date)) + return(false); + m_date.Value(TimeCurrent()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "ListView" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateListView(void) + { +//--- coordinates + int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+2*CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+LIST_HEIGHT-CONTROLS_GAP_Y; +//--- create + if(!m_list_view.Create(m_chart_id,m_name+"ListView",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_list_view)) + return(false); +//--- fill out with strings + for(int i=0;i<16;i++) + if(!m_list_view.AddItem("Item "+IntegerToString(i))) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "ComboBox" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateComboBox(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_combo_box.Create(m_chart_id,m_name+"ComboBox",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_combo_box)) + return(false); +//--- fill out with strings + for(int i=0;i<16;i++) + if(!m_combo_box.ItemAdd("Item "+IntegerToString(i))) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "RadioGroup" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateRadioGroup(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+RADIO_HEIGHT; +//--- create + if(!m_radio_group.Create(m_chart_id,m_name+"RadioGroup",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_radio_group)) + return(false); +//--- fill out with strings + for(int i=0;i<3;i++) + if(!m_radio_group.AddItem("Item "+IntegerToString(i),1< +#include +#include +#include +//--- +input double InpLots =0.1; // Lots +input int InpTakeProfit =50; // Take Profit (in pips) +input int InpTrailingStop =30; // Trailing Stop Level (in pips) +input int InpMACDOpenLevel =3; // MACD open level (in pips) +input int InpMACDCloseLevel=2; // MACD close level (in pips) +input int InpMATrendPeriod =26; // MA trend period +//--- +int ExtTimeOut=10; // time out in seconds between trade operations +//+------------------------------------------------------------------+ +//| MACD Sample expert class | +//+------------------------------------------------------------------+ +class CSampleExpert + { +protected: + double m_adjusted_point; // point value adjusted for 3 or 5 points + CTrade m_trade; // trading object + CSymbolInfo m_symbol; // symbol info object + CPositionInfo m_position; // trade position object + CAccountInfo m_account; // account info wrapper + //--- indicators + int m_handle_macd; // MACD indicator handle + int m_handle_ema; // moving average indicator handle + //--- indicator buffers + double m_buff_MACD_main[]; // MACD indicator main buffer + double m_buff_MACD_signal[]; // MACD indicator signal buffer + double m_buff_EMA[]; // EMA indicator buffer + //--- indicator data for processing + double m_macd_current; + double m_macd_previous; + double m_signal_current; + double m_signal_previous; + double m_ema_current; + double m_ema_previous; + //--- + double m_macd_open_level; + double m_macd_close_level; + double m_traling_stop; + double m_take_profit; + +public: + CSampleExpert(void); + ~CSampleExpert(void); + bool Init(void); + void Deinit(void); + bool Processing(void); + +protected: + bool InitCheckParameters(const int digits_adjust); + bool InitIndicators(void); + bool LongClosed(void); + bool ShortClosed(void); + bool LongModified(void); + bool ShortModified(void); + bool LongOpened(void); + bool ShortOpened(void); + }; +//--- global expert +CSampleExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CSampleExpert::CSampleExpert(void) : m_adjusted_point(0), + m_handle_macd(INVALID_HANDLE), + m_handle_ema(INVALID_HANDLE), + m_macd_current(0), + m_macd_previous(0), + m_signal_current(0), + m_signal_previous(0), + m_ema_current(0), + m_ema_previous(0), + m_macd_open_level(0), + m_macd_close_level(0), + m_traling_stop(0), + m_take_profit(0) + { + ArraySetAsSeries(m_buff_MACD_main,true); + ArraySetAsSeries(m_buff_MACD_signal,true); + ArraySetAsSeries(m_buff_EMA,true); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CSampleExpert::~CSampleExpert(void) + { + } +//+------------------------------------------------------------------+ +//| Initialization and checking for input parameters | +//+------------------------------------------------------------------+ +bool CSampleExpert::Init(void) + { +//--- initialize common information + m_symbol.Name(Symbol()); // symbol + m_trade.SetExpertMagicNumber(MACD_MAGIC); // magic + m_trade.SetMarginMode(); + m_trade.SetTypeFillingBySymbol(Symbol()); +//--- tuning for 3 or 5 digits + int digits_adjust=1; + if(m_symbol.Digits()==3 || m_symbol.Digits()==5) + digits_adjust=10; + m_adjusted_point=m_symbol.Point()*digits_adjust; +//--- set default deviation for trading in adjusted points + m_macd_open_level =InpMACDOpenLevel*m_adjusted_point; + m_macd_close_level=InpMACDCloseLevel*m_adjusted_point; + m_traling_stop =InpTrailingStop*m_adjusted_point; + m_take_profit =InpTakeProfit*m_adjusted_point; +//--- set default deviation for trading in adjusted points + m_trade.SetDeviationInPoints(3*digits_adjust); +//--- + if(!InitCheckParameters(digits_adjust)) + return(false); + if(!InitIndicators()) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Checking for input parameters | +//+------------------------------------------------------------------+ +bool CSampleExpert::InitCheckParameters(const int digits_adjust) + { +//--- initial data checks + if(InpTakeProfit*digits_adjustm_symbol.LotsMax()) + { + printf("Lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax()); + return(false); + } + if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10) + { + printf("Lots amount is not corresponding with lot step %f",m_symbol.LotsStep()); + return(false); + } +//--- warning + if(InpTakeProfit<=InpTrailingStop) + printf("Warning: Trailing Stop must be less than Take Profit"); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Initialization of the indicators | +//+------------------------------------------------------------------+ +bool CSampleExpert::InitIndicators(void) + { +//--- create MACD indicator + if(m_handle_macd==INVALID_HANDLE) + if((m_handle_macd=iMACD(NULL,0,12,26,9,PRICE_CLOSE))==INVALID_HANDLE) + { + printf("Error creating MACD indicator"); + return(false); + } +//--- create EMA indicator and add it to collection + if(m_handle_ema==INVALID_HANDLE) + if((m_handle_ema=iMA(NULL,0,InpMATrendPeriod,0,MODE_EMA,PRICE_CLOSE))==INVALID_HANDLE) + { + printf("Error creating EMA indicator"); + return(false); + } +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Check for long position closing | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongClosed(void) + { + bool res=false; +//--- should it be closed? + if(m_macd_current>0) + if(m_macd_currentm_signal_previous) + if(m_macd_current>m_macd_close_level) + { + //--- close position + if(m_trade.PositionClose(Symbol())) + printf("Long position by %s to be closed",Symbol()); + else + printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment()); + //--- processed and cannot be modified + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for short position closing | +//+------------------------------------------------------------------+ +bool CSampleExpert::ShortClosed(void) + { + bool res=false; +//--- should it be closed? + if(m_macd_current<0) + if(m_macd_current>m_signal_current && m_macd_previousm_macd_close_level) + { + //--- close position + if(m_trade.PositionClose(Symbol())) + printf("Short position by %s to be closed",Symbol()); + else + printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment()); + //--- processed and cannot be modified + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for long position modifying | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongModified(void) + { + bool res=false; +//--- check for trailing stop + if(InpTrailingStop>0) + { + if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop) + { + double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits()); + double tp=m_position.TakeProfit(); + if(m_position.StopLoss()0) + { + if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop)) + { + double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits()); + double tp=m_position.TakeProfit(); + if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0) + { + //--- modify position + if(m_trade.PositionModify(Symbol(),sl,tp)) + printf("Short position by %s to be modified",Symbol()); + else + { + printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment()); + printf("Modify parameters : SL=%f,TP=%f",sl,tp); + } + //--- modified and must exit from expert + res=true; + } + } + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for long position opening | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongOpened(void) + { + bool res=false; +//--- check for long position (BUY) possibility + if(m_macd_current<0) + if(m_macd_current>m_signal_current && m_macd_previous(m_macd_open_level) && m_ema_current>m_ema_previous) + { + double price=m_symbol.Ask(); + double tp =m_symbol.Bid()+m_take_profit; + //--- check for free money + if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_BUY,InpLots,price)<0.0) + printf("We have no money. Free Margin = %f",m_account.FreeMargin()); + else + { + //--- open position + if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_BUY,InpLots,price,0.0,tp)) + printf("Position by %s to be opened",Symbol()); + else + { + printf("Error opening BUY position by %s : '%s'",Symbol(),m_trade.ResultComment()); + printf("Open parameters : price=%f,TP=%f",price,tp); + } + } + //--- in any case we must exit from expert + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for short position opening | +//+------------------------------------------------------------------+ +bool CSampleExpert::ShortOpened(void) + { + bool res=false; +//--- check for short position (SELL) possibility + if(m_macd_current>0) + if(m_macd_currentm_signal_previous) + if(m_macd_current>(m_macd_open_level) && m_ema_current=limit_time) + { + //--- check for data + if(Bars(Symbol(),Period())>2*InpMATrendPeriod) + { + //--- change limit time by timeout in seconds if processed + if(ExtExpert.Processing()) + limit_time=TimeCurrent()+ExtTimeOut; + } + } + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Examples/Math 3D Morpher/Functions.mqh b/BKPS/14031218/Experts/Examples/Math 3D Morpher/Functions.mqh new file mode 100644 index 0000000..1f27019 --- /dev/null +++ b/BKPS/14031218/Experts/Examples/Math 3D Morpher/Functions.mqh @@ -0,0 +1,372 @@ +//+------------------------------------------------------------------+ +//| Functions.mqh | +//| Copyright 2000-2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ + +//--- custom function y=f(x,y) +typedef double(*MathFunction)(double,double); + +//+------------------------------------------------------------------+ +//| math functions | +//+------------------------------------------------------------------+ +enum EnMathFunction + { + Peaks=0, + Chomolungma=1, + ClimberDream=2, + Granite=3, + Hedgehog=4, + Hill=5, + Josephine=6, + Screw=7, + DoubleScrew=8, + MultiExtremalScrew=9, + Sink=10, + Skin=11, + Trapfall=12, + }; +//+------------------------------------------------------------------+ +//| Names of the math functions | +//+------------------------------------------------------------------+ +const string ExtFunctionsNames[]= + { + "Peaks", + "Chomolungma", + "Climber Dream", + "Granite", + "Hedgehog", + "Hill", + "Josephine", + "Screw", + "Double Screw", + "Multi Extremal Screw", + "Sinc", + "Skin", + "Trapfall" + }; +//+------------------------------------------------------------------+ +//| Function Peaks | +//+------------------------------------------------------------------+ +double PeaksFunction(double x,double y) + { + double res = 3*MathPow((1-x),2)*MathExp(-x*x-(y+1)*(y+1))-10*(0.2*x-MathPow(x,3)-MathPow(y,5))*MathExp(-x*x-y*y)-1/3*MathExp(-(x+1)*(x+1)-y*y); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Chomolungma | +//+------------------------------------------------------------------+ +double ChomolungmaFunction(double x,double y) + { + double a= MathCos(x*x)+MathCos(y*y); + double b= MathPow(MathCos(5*x*y),5); + double c=1.0/MathPow(2,b); +//--- calculate result + double res=a-c; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function ClimberDream | +//+------------------------------------------------------------------+ +double ClimberDreamFunction(double x,double y) + { + double a= MathSin(MathSqrt(MathAbs(x - 1.3) + MathAbs(y))); + double b= MathCos(MathSqrt(MathAbs(MathSin(x))) + MathSqrt(MathAbs(MathSin(y)))); + double f=a+b; +//--- calculate result + double res=MathPow(f,4); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Granite | +//+------------------------------------------------------------------+ +double GraniteFunction(double x,double y) + { + double a= MathPow(MathSin(MathSqrt(MathAbs(x)+MathAbs(y))),2); + double b= MathPow(MathCos(MathSqrt(MathAbs(x)+MathAbs(y))),2); +//--- calculate result + double res=a*b; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Hedgehog | +//+------------------------------------------------------------------+ +double HedgehogFunction(double x,double y) + { + double a1=MathSin(MathSqrt(MathAbs(x-2)+MathAbs(y))); + double a2=MathCos(MathSqrt(MathAbs(MathSin(x)))+MathSqrt(MathAbs(MathSin(y)))); +//--- calculate result + double res=a1+a2; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Hill | +//+------------------------------------------------------------------+ +double HillFunction(double x,double y) + { +//--- calculate result + double res=MathExp(-x*x-y*y); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Josephine | +//+------------------------------------------------------------------+ +double JosephineFunction(double x,double y) + { + double a= MathSin(MathPow(MathAbs(x)+MathAbs(y),0.5)); + double b= MathCos(MathPow(MathAbs(x),0.5)+MathPow(MathAbs(y),0.5)); +//--- calculate function + double res=a+b; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Screw | +//+------------------------------------------------------------------+ +double ScrewFunction(double x,double y) + { + double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); + double b=x*x+y*y; + double f=MathSin(b+a); +//--- calculate result + double res=(f*f); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function DoubleScrew | +//+------------------------------------------------------------------+ +double DoubleScrewFunction(double x,double y) + { + double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); + double b=x*x+y*y; + double res1=MathCos(b/2+a*3); + res1=((res1*res1)/sqrt(b+1)-0.2); + double res2=MathCos(b/2-a*3); + res2=((res2*res2)/sqrt(b+1)-0.2); + double f=fmax(res1,res2); +//--- calculate result + double res=(f>0)?f:0; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function MultiExtremalScrew | +//+------------------------------------------------------------------+ +double MultiExtremalScrewFunction(double x,double y) + { + double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); + double b=x*x+y*y; + double res1=MathCos(b/2+a*3); + res1=((res1*res1)/sqrt(b+1)-0.2); + double res2=MathCos(b/2-a*3); + res2=((res2*res2)/sqrt(b+1)-0.2); +//--- calculate function + double res=fmin(res1,res2); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Sink | +//+------------------------------------------------------------------+ +double SinkFunction(double x,double y) + { + static double k=5.0; + static double p=6.0; +//--- calculate result + double res=MathSin(x*x+y*y)+k*MathExp(-p*x*x-p*y*y); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Skin | +//+------------------------------------------------------------------+ +double SkinFunction(double x,double y) + { + double a1=2*x*x; + double a2=2*y*y; + double b1=MathCos(a1)-1.1; + b1=b1*b1; + double c1=MathSin(0.5*x)-1.2; + c1=c1*c1; + double d1=MathCos(a2)-1.1; + d1=d1*d1; + double e1=MathSin(0.5*y)-1.2; + e1=e1*e1; +//--- calculate result + double res=b1+c1-d1+e1; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Function Trapfall | +//+------------------------------------------------------------------+ +double TrapfallFunction(double x,double y) + { + double a1=MathSqrt(MathAbs(MathSin(x-1.0))); + double b1=MathSqrt(MathAbs(MathSin(y+2.0))); +//--- calculate result + double res=-MathSqrt(MathAbs(MathSin(MathSin(a1+b1)))); +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| GenerateFunctionData | +//+------------------------------------------------------------------+ +void GenerateFunctionData(double &data[],int &x_size,int &y_size,double x_min,double x_max,double y_min,double y_max,MathFunction function) + { + double dx = 0.1; + double dy = 0.1; +//--- + x_size = (int)((x_max - x_min)/dx) + 1; + y_size = (int)((y_max - y_min)/dy) + 1; + ArrayResize(data,x_size*y_size); +//--- + for(int j = 0; j < y_size; j++) + { + for(int i = 0; i < x_size; i++) + { + double x = x_min + i*dx; + double y = y_min + j*dy; + data[j*x_size + i] = function(x,y); + } + } + } +//+------------------------------------------------------------------+ +//| GenerateData | +//+------------------------------------------------------------------+ +void GenerateData(EnMathFunction function_id,double &data[],int &x_size,int &y_size) + { +//--- + switch(function_id) + { + case Peaks: + GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,PeaksFunction); + break; + case Chomolungma: + GenerateFunctionData(data,x_size,y_size,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction); + break; + case ClimberDream: + GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction); + break; + case Granite: + GenerateFunctionData(data,x_size,y_size,-4.0,+4.0,-4.0,+4.0,GraniteFunction); + break; + case Hedgehog: + GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,HedgehogFunction); + break; + case Hill: + GenerateFunctionData(data,x_size,y_size,-1.5,+1.5,-1.5,+1.5,HillFunction); + break; + case Josephine: + GenerateFunctionData(data,x_size,y_size,-200.0,+200.0,-200.0,+200.0,JosephineFunction); + break; + case Screw: + GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,ScrewFunction); + break; + case DoubleScrew: + GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction); + break; + case MultiExtremalScrew: + GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction); + break; + case Sink: + GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,SinkFunction); + break; + case Skin: + GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,SkinFunction); + break; + case Trapfall: + GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,TrapfallFunction); + break; + } + } +//+------------------------------------------------------------------+ +//| GenerateFunctionDataFixedSize | +//+------------------------------------------------------------------+ +bool GenerateFunctionDataFixedSize(int x_size,int y_size,double &data[],double x_min,double x_max,double y_min,double y_max,MathFunction function) + { + if(x_size<2 || y_size<2) + { + PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size); + return(false); + } + double dx = (x_max - x_min)/(x_size-1); + double dy = (y_max - y_min)/(y_size-1); + ArrayResize(data,x_size*y_size); +//--- + for(int j = 0; j < y_size; j++) + { + for(int i = 0; i < x_size; i++) + { + double x = x_min + i*dx; + double y = y_min + j*dy; + data[j*x_size + i] = function(x,y); + } + } + return(true); + } +//+------------------------------------------------------------------+ +//| GenerateDataFixedSize | +//+------------------------------------------------------------------+ +bool GenerateDataFixedSize(int x_size,int y_size,EnMathFunction function_id,double &data[]) + { + if(x_size<2 || y_size<2) + { + PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size); + return(false); + } + bool result=false; +//--- + switch(function_id) + { + case Peaks: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,PeaksFunction); + break; + case Chomolungma: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction); + break; + case ClimberDream: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction); + break; + case Granite: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-4.0,+4.0,-4.0,+4.0,GraniteFunction); + break; + case Hedgehog: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,HedgehogFunction); + break; + case Hill: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-1.5,+1.5,-1.5,+1.5,HillFunction); + break; + case Josephine: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-200.0,+200.0,-200.0,+200.0,JosephineFunction); + break; + case Screw: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,ScrewFunction); + break; + case DoubleScrew: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction); + break; + case MultiExtremalScrew: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction); + break; + case Sink: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,SinkFunction); + break; + case Skin: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,SkinFunction); + break; + case Trapfall: + result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,TrapfallFunction); + break; + } +//--- + return(result); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mq5 b/BKPS/14031218/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mq5 new file mode 100644 index 0000000000000000000000000000000000000000..2ecc8cb9f707a6a78a2a2ed1f037af5b48b7f16e GIT binary patch literal 35776 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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D Morpher/Textures/checker.bmp b/BKPS/14031218/Experts/Examples/Math 3D Morpher/Textures/checker.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0d65c538b8a39a3d5491f1c40a5a63e7eeb26943 GIT binary patch literal 196662 zcmeIy!3l&g00q&=Hem@{fd%Z{=F^aCND=Qc0Y&jJF!S+uU*j{@x!&u$9*%t-<6Lj= z+28l`zCRsmV0Neh8bA0$;|HHj&>Coh)_|=a-PVuZ0Cog)_|=a-PVuZ0Cog)_|=a-PVuZ0Cog)_|=a-PVuZ0Cog)_|=a-PVuZ0Cog)_|=a-PVuZ0Cog z)_|=a-PVuZ0Cog)_|=a z-PVuZ0qocsqqjh7paoh3wtjS5KY9za z23nvsVCzS>^`o~yYoG;M1Gav2TR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAW zpfzCYN4NE(w?J#41zH2Peso(udJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvs zVCzS>^`o~yYoG;M1Gav2TR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCY zN4NE(w?J#41zH2Peso(udJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS> z^`o~yYoG;M1Gav2TR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCYN4NE( zw?J#41zH2Peso(udJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS>^`o~y zYoG;M1Gav2TR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCYN4NE(w?J#4 z1zH2Peso(udJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS>^`o~yYoG;M z1Gav2TR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCYN4NE(w?J#41zH2P zeso(udJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS>^`o~yYoG;M1Gav2 zTR(aWv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCYN4NE(w?J#41zH2Peso(u zdJD7$TA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS>^`o~yYoG;M1Gav2TR(aW zv<6zBHDK#UxAmj9Kx?1{S_8IzbXz}q3$zAWpfzCYN4NE(w?J#41zH2Peso(udJD7$ zTA(#x>qocsqqjh7paoh3wtjS5KY9za23nvsVCzS>^`o~yYoG;M1Gav2TR-|Ap@6C! literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Functions.mqh b/BKPS/14031218/Experts/Examples/Math 3D/Functions.mqh new file mode 100644 index 0000000000000000000000000000000000000000..40aed1c5efbcc92dcb88e4d3b4e4da01eee84951 GIT binary patch literal 16008 zcmeHO+ioI95bftk`GGj&&m_N*knVEBQ zg{!IAHJ9d3^8xdJtOU;yVIyU zZSYLuW%L5{eFR&J-NSs*_mXgkARi?bp?5x;|$k* zth<9XYyZR?+1W0!&LJ%ICH{u!b%}o6px+y`^daROIvAq$%b@i~e0Pc&hIY;~v_Fg5 z&oR#!-_zpV>^}qD6r&~>cMj>4{5*!W|<3C0{-EEkxu1Gf5jkIjW`V@s&V_f|g>>?dV&rJX>7pFAtrG}egM{S8{4 zL0i|@2l}5r{wB~d_l0|Yjn8D1w8VCsz=GyzqkV9+vWXUcjZyR)dDbiT>b&kI=|`Cw zV^7Q*tFOHF2J9`LuTDSWdt&b9Nlp8UUM_=U#NvfS*HiF`J9PryHI{qjut+c8o5(jO zunO{(pR)bSp~r3+Bk!@j5OuY9#4XtURXl*s9UFbFMrpH>PSd*{61SWZC1ZMp-6m zD37^}w5nI2F-&=sI-+_c5;NTgiHxWkNgShh$*1We?{m3kxCZId!|=tv_V2 z`UI7eKfmk2ssQU}GE<17{CGuLgmnbZ(8oFli}h5=eqE1xnvwN1&m!Gzw?_!`N5|ZC zUDd%OggSXFKcH5qR(T)4;Gg8NAK>ZPjcmHeAH+Dy`-d>1D8^AGkNb!-)IW&bZZ~J+ z+RD1Ps&ebV*;ps*WNim$(nDCv`+h}C%|EgG80qFL&&U|1p4cw#fB0!#ErUBa+{+9o$nr zTBV6AXJqFz$}7c!x0|=_zRr62s?zJgTc?xt^0k3;qKDT$Z2JeiAL0yQ1%=ht?-t+c z8S?`5A6hY=xM80?Tai6n#+=#h>e3t4+nOzLF@Hcl(c zNMV{hgOkTbt=RUk))A16BK+IU$(N{~>vLw#7L`HO|E~ilvvu;s&+K!|&qg&f9KdIE zEmK>zQtWeFILT4;K>De*ylP_XbXkKY-#cJr+eQe*btI9Mm8lAzHauD$9*%N&y6C6U z9*&3pYh<5$yz^Gd$im4M&8&(nr2i^EMz%^%@nzpH{Q3yqe*b@z*_L_Yp-RtI2cK3( zCr=*k$-^~J$Py};@p z=T!%Pr8=q7C-FBKd=BLt*-gxJYM#&B^Oq*!S-EP|1f!mNqgL@mthdZru53tWL16~P zn*IeM7R{Ahjc|f*rEeQmL*{zvr)##ITkCboGoekSU3@2z!b4)6dT!G3D?+(c* zzPI2{isYXL@*Q%Xa#_fwKi^yUT~m?dVIWy+B#NAMOpzZVmr;Cg;apYuRroFOZ9S{+ z9jleLUBQkwk1%n&y-xhZ?z+8C9ZvLEC+qe;>M6?KVdmX5`VrPhSKWySJx1OWa}I+< mx^tY=-P8w>g$E^!0v@MFB=bhy$`$x^zUm7`YFB-fOlnWas3zI?^3+omk;WrvA_^O1^6o< z;Q~o{pjZY2qFX4^HAS1fPD3shqH(N9pH0d0`M_F^+vu&0;7TFd~;)ekAz=ZU-G{~Dk%dw(#K#>zBp?YQR^3 z20&}`!f~=O!rl`|0BnG-fsbYT6WjdY zDS!w%7eHY=n3L9mYGn~H6(IiefWOPn3mw(QTtEjn4qO8yH3In&@DyM&D8cnV75JgG zqdh?Ro&iuT&jM&IX}`Wy?!ifI`l6Ox$R}!x9z2zmxNet21KNhbn-mY`ptFJ2ndTh@ zNX}JAijDLX+f3jCsXg)S0A%?^%5p>B7P)@DY`@eG?K3XNf0ONpo^nWaKx^?ovVHQ` z>R;9U0?tj~-wOEvyqYH#Z&>YR8}T`i_-c|Njj^iw@hj?@A99HHJz-DhYt6Zd*>s_6xy>5E$$ z$PW3aBO8*`p0l*!-i9rAM#|3F+coB=dk)p*F`xw?ZVkY5bxl5?r!z?e(78&r9DFv^ zz7Em{pndjS&J@i}cEC`8>X6R2{{mEh+S9%cNs2 zL-xq6d>okXpMWQE89kYkJ?R*KSJllIiMI=4=B8^$@<`~Vfz+9 zdvx{AUDwU9<~fKv>tz7j+}U3?mdyFGv2><}xPTBxmH>4Y_KFKOOr%fA*55yNEk& z^~Oh;$yYmS3yL~hv`rpUUQ!9*cM~<9g?mCCcxQ5YlGG;s+@%fKWCxuVH#g>@T<-&@ zeuIG_Tp!1QYrl$=9}Bfh~3TZsNba{zPDgS&28lB8tmg~i~_`?4z7|NazXi`d(e*n-LI%lRpn!n z=OEwTS6k6o%<(4hGf)mh#-H+{7!;n7h<^`oa^bhF(GjPglb*%iaN zEf@4win5GVIty&avii$TU8y%a%76IzQ4Edg3&`c^rK`#_H*LG!cp>vgL_T05A8E84A^H{kZ7P$lWj7%lWL;rW?1Ltl&3jguWvmLABW|!a7E2IoTb$p zw`Ml2+f+*D$uIJ8%eMRCz}d;h&FM(K%-Hng6Pqxe573!o3w*fno7NBg54WFbta~J` zIJ{QEJJUq9Ic(prHxBJJz8R=xoE@;wABdasT!+V{lL+4!E(_Na4y`jEA_$39|{vt1K!_lsJcjfz-ZaHWv>-+K#b4U ziEPoPbMtRNkM|8lV`Y8QHD`mdbpH&v7JsZkRQs@@GHf%;GW?j`H5vKfl=jBd!~67; z4{ICV3eqyV8L-#ra=>n*7#YL{?lVk5e@3W|W_r5Gq&ljVGXLdFTv7Na@}#g_TRWxo z$4&Px;~we&zC6PEEfus+=voJmJRkNJAL$Vv@ua;fc{b#1(WYmn4}g&X-RmWJ;J9&i ziX>;l7@G*h)|}SCdVkEa%s%UiFHg@)|aJ`%iFH{|dhyMlNoNI z+ZJK2Ex2f~CMC;sgqZ4~GHeU0Z|ErVIn?eBzB_-}TkKC#ik~6hlZ_P|-Xji>8UQ_; z_NaSVTiI*ay$ej0j-`A&_uK={{{XziH-b7#oYh#q>8DTbm`%7Dt-CSwwC?63Q99d# zBeZt}ownA$6K<*3aKcirI#f^R6gc_>@73`JXMz_=YKQFA@eMQ5OANQte{f>IZfUsw z?x<)Boka3O{!$Dz5^~Lkw&oxYqEp(eTGVy#P@pgjoY%`>F7ZIT^gV*UAFPmaP`Ec_ zIV-xBj-_X~rGVu94xHZuEL-zp9}9dIu{_g3oh4R-uHUg#bGT^mec*Zh^@q;tZ8&g7 zcazU4oh@GHtaUGhYyaXJZmM}Pf@jct!pfi^R8RXL@?ggy%vd+_1kbQ8+*-dp+;DGb zxYkY=@OHmotrbIl$RGJ7|2Ir#rsSCoX)Cl-W%coPtU}nCvfr+4J94lb&&l7|SVYZ6 ztX~7;fC0oo5x1Aoabw}NOEDJ!&6 zsS@yqyH`34F)Q&~bUfW$-Sw);689@6OI?zUmpdXp`*@?3HnE1^SzLD9dkh?mqV;~# zKdrk(2i!EH^miCW@pR%&IvF%ZS!vQ<(Ih?flO5T|7<_M<==kdi@Kg4BQjLy$D8`N3mvyeT=jcG3}>pW;|-S!#B<@fLx2@80v^J!*P*e0y^C#=X~ zP)&v15T8<~FFfwMPCZuSGCm;NeOdIa{j=TD_s?~{X|C>&W;Wjzu~}U;)i6&n`O5g3 z>yD#XGo1v(m6}+?-LVF1ccG4VT+shvd$hX_BS~%2Q$N{}eTvC4{p+sV!pIN#BfsRI z=Arp+S*ZuycK#;j25<4{46E6}_brAO;0)@jIJk^GuFP(3f5Nn}Zg0H~e~g<7To#?u z#Cm_i3M~eS%WVgTV!drS2pv@H^BpDyWVtOrpJ}Tede3T_>s`xfcDF5N*xa_5xgRl_ zq?^yxzv;0#IMr;y-fN~ByM8lWvOUFQ>Cec^mSp2)n=W|nV=TvcF+IU;CEl zPe;iQ`6IvN|E|pp&kVZ-5gGRLPiMJ)buq_kk{5?ut8qbv7RnX*W}h-)&?<(S6*Pzh z9^mra`OVdbtc2YNAfo<~byu*a#pko_)k5w% z&OLe0e&(TEn~A(!>j`GrR+Egfttac<^H~>!xOd;NoW2trwq{t&+5%1+GxpEk5a<0X zBPnS^PyJ*^_Ssfb_GS63JwkrSUk-1Q!(E5j!FTy{BXjJg2Hdw%b-(YvI0i9z%cF?* zd03Ig!aeQ#}Vd-N&#{lwS(J4;=rvV#4Co|N$hUlDlEx(MDL@+h|- z>RoC#!WZx<@|=IM)OMt6vE3K$dHkt|vz%w0$m37(D6;*+1aax-`K>x!z#Frtz(#dv z0Z;Yke4BBb^Ldju6*$e^oOJM4cHd#IU z&bO8OEI^$P?iBC_-vi%+fPb0S^mvl85ZWsrtgu(%a6sTSGZt+xzzuK|@JF~5I8O@9 zbD4g$$Z;&c*neqAh5gWdz;5JiXN8OEj+&5_nhh6?%?6ITA9iG4 z<}lo#*l$T_uFLeWLZ@+l<@Uq)|BAz$SvI0u(`PD>)$2ZG8x)e_Ku z0Pq2*R$KsnIsY@~0+-2$OAjnMCU6?XgHET)d8BsT(UqnTu6y}DE{Ho-krB-v-;aqx z+pqq_dW&i|Rb8QjvR<+CSf_l~X-7)^=7(4ChdPiysbBI>^U!>U5MLr>U-3ye2wlgV z5FTEUSRJ~qtkh{zXNiq+7RF5y*bL^Cd8v0iymLbMDEm}y^JVMQ>cd~f3tT58l{t>Q zSne_TD(sH;fv|FqsVUMJ0wJkZe1T_q5csN}L>`V7xK0hMJh;fYImtHgaZy72gS(O0 z&FM$jNja0u`Nyvw|2U8rykM0czR9L?wUf(FAVyQVSjekMD3|<$v&4;8_!Fs@?UVUlCR>7vF>Hw zGh(EE$RGJ7|1=NH7m4`NAfJm1HFQ?sI5Mf!X-sNmz?Zk1E*hk@-is)xJ)_-J%p1`q zuo?6e<0jGB5BUb}>9(adgF7pORy}=~9#Gs6we<#SF}~bw+--s5=V_?lTNV7_$*_%; z!$s_u4Cu}R6h{;g0X)k^nU~sS@bMQNS`gBl;&`d{f=N{#Z`6%Uw?#W!g?HF3kENQq zyf2a}gV!{--Z`GyaBBNW%uQuH5mn-|&2rS>`z6 zYL%Pn<=Uw21rO5?6;_6t=er&cth0BF%MD?WEIY|Zpqy1GShgJpTlTZ%fJTx>Ncsy13n)N;k?dTpRabd}?=sMVo%Z(tnNSsJ)gUh|OS9GsEq(4|(mjLwIobK(j>H9}_+orx4@ z3~Dq(bZ}k*_I*b6ksq4zu0;7)1Ew|=rZAG!#{G7EiOtZi=HJ|l8%}P&R_#7Emg*0E zWX+sZv= zv^_}m$rT-0Sy$!sSsUgm1@3UboVl2<7<;0i!g*8)^t1&nneY1g?4LNbdf2OoOx723P0pYej5(I?>wNq)&c z&4V>o$->;FIG>8>8agh%eC)Sok^kJf<|Mnq3crQz;G`+fv#&PR=wN-cc3s0I%i{h?n3 z%m?Px-Z?}3=Skb7Us7s4D6c8byskccL!Quc66KcmIQb*LS*YzirL}W=7yv-A>Lg8@}-ycpiN2yAX2VP;-1^yEwtJOmt{|HqH~;i?kLrH^ohP5D6WJH$qZADsd)= z5MLeQtExmUME>f+rb}imRRPPMf>#i1Rsr7tl!xWQYeD2^xwK7s>R*eqiZxv_Z>bGi z(}-uL3gop$>bC~{lDQzOQC}1T@kXA8NaBP2?YhwK@~MWvAyd)&pX~E5E4#s)JT^G@jFHt@fVQjC_)R@-6WX z`4H$tUPzV#Tug=4UXx2OuDUwt>vnM1F3TVM==UP@{r7$O^@ooBK4Ta_-$*5SDD+zr zTy;pJqdD23xi)xN9db)~rn7(pt-)ioX$|O{Yyp~aW;WLbEqN%u%xkYYsL@qwKaB3( zn}MGI%ENkKUCAXE;=fMXCjC#~y0y?{f|41_0Vo%niZ1Yo|0ZfE2H`N-g zdH4L?b3cm(_snM8w;$FXTi=1W&B1}b|I)WW;zR5H+&-7(&t1cA05G2TXFIEH6S|FO zE!Vv|8cywaTH`zY335R3NTK}n*)?(Zp4x#JSj$!SE}{EGR_ZYg_ip9Ac&9PTahvU( z=Q^E_=cv6Hv%MhNocM1qaT=qSgB<0#&2SYsj?#y2kI-R=VY%Z-))Z&jg=fc3?k zD4Lr;v>o@%C*nBMjtZwyEb+j$`QSj`e`)>u{M{bMTV4`>jGdM5G%->XvJyG)WOzPh zr~_8z@;PExruZeY%6SCCx-%(vRvY#`tFRmV0PoP3V50?K?Unaojjh4e@4m|vhx{l5 zhJ3i?y3O!HZJ5A@@idUmq1Xj*V`J-oqZG`7!JTRu{U8A>R_tIOkd2(QjGPd2RL} z)tfbf=y@DRaM0kcUsYo40&Wb}Vg%kD zSmRku_Av7ZYq{pZ@Sea>Z%mwEMfJ`eW`wY&SYuXUuS{z{g~n11AuKH|oa?B``&F(n|FiGtvg7a!uaECwtlDQf69p`0)xI+s&To3QH<7iYYmPss2gf%7bD+J# z3E!Q%_r>R2zpUiO!mn$?$sMdY(FXhOJ67X8g;lwYX4M`O81BoG8f?0#PxGIU9Z%Qr zp)9X^**3=Z`kNul)ejg~aCEaprsvW%XM(N1!8xG{^!Qy8$3cEh@P6+?kRg-T%eJ|( zm}hV$e>iKo;>_?3fi*_&X7wk2WOz@M|basBt5^3r8a6tugYZ< z)_)Ic`OSriV@+6%*A&`Aj=jYRAJ6_Sus56EqlbTmzdb>`^m~$dQVt6D5&EB7f9U8L zlbZn2`xq_=QK=+U74#qB3 z;8BN{yml~VRwo03vnKfwU8K&gLMf5AXB`*jR>JfI6 zZB8nwcaR#6Xcqh#m@E-W{Vcns5+|k2XF{s)C+OA;;Kozb_@gZK%lTI?>DJG=-YqAl zbj$wIaY%~f&-3waRFNwW&$HibVL{SrVYfUpP$F4^GO5wg-RxC%C`-(kyzEl%)^n0sp#8rfG}6TY literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Math 3D.mq5 b/BKPS/14031218/Experts/Examples/Math 3D/Math 3D.mq5 new file mode 100644 index 0000000000000000000000000000000000000000..f95451d8f52512bd6eec2a7d448be9a17bb1594a GIT binary patch literal 6986 zcmd^DU2hXd6ur-t`X4q%NUne+qT&VQhc+Y?QbU3<5vc?^ti!D1gAQs0K`V8+!s z?&cWHmKq)79=(p&4QM@8YYp%}hs`pb@tqN__v$D1eiyQiG3Rq#+|8GJHQ+;iSo0C~ zn8@?<(LuBiJ>23gQ>+tUqgPB+UJugf2gEQ_T(jhT3HI@3&+NXlb=v zc^ShKN7(Iw$|qlrAp`mxcwXT-<1Y0V*DGCZ!JF4{{Zn}dYNa4El^65XQ=W2V#5l^p zRgP6gFcDKP8{23IOZA{lCa()VK%0B)7a7ZBTNaR0TsIBtnlp)+en77@-x^{xRQ*%` zU1cM%|8GViXVxhv(8I~d9{%aUWTh#;sP|Lb4?2qdj2<-9{JSl`DVNN}%qNV-BghzF zMiz6hU7aWBW5(wY&o*TZ9`^(}ohbM&|LMm^YPII_ZWl=RrGvY>xLyDO$9wV^m;-8) zYuIC(v5w5}>#5Y=vC9HGHz4D3Il=@H(9jbNDzzmU`Ao}L`e~I}^=>nxy%JA&ZJYhL|4b0p= z_k@_o)o}w^f!^>AQm5F{_T~E-vfn~$x>fc~)PYUd%JM}liJZ)VhwnFG)yKFxs3AL$ z{0N@04c1rR`&97I;8#`hp2{<5zXf@eSd<#%)hSLHf$aTa3o}9(uiqs#G|xWV;L3fNQ&!eRO};y z7=O&rpOJl$4uJ0Gug;R}uR#fYdOmFrd&Mu!|?`hq8 zUnAY}M0KVNj1{}D1+-xHnyN0G&7iUMoz%`(c*cn51I**xQnkqT=S8`% zkVV;3dgKt#09J8+h>7pUYlbUk)wx^kfLVV6pMj@+%gjb#`-q ziX(%k%mMUx16#3!EI%bOr?U^BJqL(JzQO*eALU~2KZ{Yo?+UEBYb$YjaiBIKX zhqZC-qG#&hYD2FsY6@%19%gN$11;o#9233BSsXg7NhxZ*dZ@eqrNZBv?0gV{oMKxxs(5$?ofHrajUVOC8dCcKm3F&sw+I;jy865`9d;I~Ax18axqHf)kGXpAWKiZdg7?I&mb)}>tR}W$Pu%s$jW*C?4V_x-P_XkGo5NG^ zG-LLFQQsPs9mnjH+9`7ZPq<4@X;7fi46Qr%*!@16t_G++VUtZp(pnZN(Vwwn4%dj4 zv?5zl*Wr=YF-PC&*mKA;_AEKYafl`(hhaCeTw>3_bLLj$m1IHVWyyjmQv1w%uO;@> zc6jm}bL=DZm(H(#zXW}UP{<3?VRBBq#6GSb93gTPvQPG zF2JC*HX}uaymE}M6VS;&diEG%>XxHCfvU-9jIFh|xV^^m>jZs;IkxA>d8KOmGLlNE zvPc72@?p$hwSZ*Daj{;Z9b&CZr~MQ;LfKnHl=pTl*T!1f z`8s1Eo>2_%L zT%<~Fh$oLom_t678ZJXL#2#Z8_scl`E~XY0?|_=r;d()I_0VkYaziu9pp^JgmR^6p zKh&}Pe%F`3#=UnH_d*?>wwXyLcPa*~?ApQWw;P#c>^K_wu!E>RCpmuUhQCm0}D2d)Dypz4xx; z2;ExT_uaN%tDdsdi^u1yvX5ET*R>sW8C^QlDBsk{A2aS!V}362uKS!nhfHUl33XFl z^bS9rS|+u?wu8UsAXAUuruP#zom3yb*Peq#y{pcXgIXZk2S=a08c^f)oum$4+Q&a* zt~y|OiC2_28UE2Zp&n7!qCV)$%>`ZKId@eERrYbs>P5Y(U)x3CX)W@q%@-?w?tb`h Xr9<~t%J^cc47%&O7kb1MzH|KmV{T=I literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Chomolungma.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Chomolungma.set new file mode 100644 index 0000000000000000000000000000000000000000..09a45991e367d211dec2055272376dd3072d9413 GIT binary patch literal 684 zcma))PfNp45X9#!_#JZdqSAVmo&-VAtJq_W&l+r#&?KVbXIFo-kJO5XO33>&yE{8O z$=Bz(3f(GcqfV6?)!Z9BvL5M13-x-^1^Y^+238|EuOp+NDuEO_)Pc<9{0g*yqar_X zDucJDwu0X=?=5_;Y{56Y>tM=CT-|_LOB)^6)VxRC5_F%k0+=$@XuM#t#9 zJ#_c0txNXI{@rhV-sfPRv8KlCGp6@995{dQcrLr%Z*K{=#)v)7=M-PCBrh?SIkToq km};gT|Am>RJJCD(O@iS>XR%Lo3NnpzM&>*D^MB=k117(F_5c6? literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/ClimberDream.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/ClimberDream.set new file mode 100644 index 0000000000000000000000000000000000000000..3536542206ad9fcc17dc6d2c2e5fab715cd2ebb9 GIT binary patch literal 696 zcmb7?K}*9>5QOI}_#blfqEZD<(vu(vdKG)D@mYg52~8?0{&w}7eI`~s6e)e#x4Sbt zJIUwAsR~^yX{An;8r9qz-E;2gN^|vk&>7Dsm0EK;llwY43Q&nmpSb0az+IpB4dW}koteN+@m+V+^J`!KT?n!?g{mnY~VU3>Y&1-ZF z&f7yzzZhMzXZG)Q^m&_udB+-z*{5vpceo~g=jXlbdOzM0ZVeTCp5qj6u%s`smpQYh lbC_zj9=?UCjyI||%$o$mfsVeTi4KWQB0J<}8<^R@Fkk1ee9`~_ literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/DoubleScrew.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/DoubleScrew.set new file mode 100644 index 0000000000000000000000000000000000000000..61c3cbc4d1a211fbca79f0e798b0cc108ee6b43c GIT binary patch literal 684 zcma))PfNp45X9#!_#JZdqEhi9NKb+w=vC~o#%B$+NoW#L@w2PH*+*){LnY+>ncbb8 zo#gBDT!n6xv{t7|jcV?V9$61`qq%xL>4N=Pr3O|bIjm-2!x%vI4GGD$V8|b3N#V>MmG+ zv^KD!ETVuqY=W~iLSdy2R%bZ!$ lB}_F_kN?6{XIs%b`b~o2NT;z+bPRG5=Zws@@@N0b{{|`%d;tIe literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Granite.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Granite.set new file mode 100644 index 0000000000000000000000000000000000000000..3356136f09f8e15efa34e38bf530803dbf8d1a99 GIT binary patch literal 684 zcma))PfNp45X9#!_#JZdqEghG^dty^Ud0}3eAZB#geDOcKfC&yeWX@AR6^dL+1=UM zNxnYMRp?epYjvvBsOH}2k@Y|~nyc57F4&({YG5^z^ExsLsuD<{eeKCy&aXfVI4bfJ zr!shZYAg61^WMVe$`*Xhy9%bP#MKR`wY1T3Ma_HEEkJiEE8u#i(roTA*MnZD?t=A4 zYeQ^^8LY{fR+gu*@(#?}dYBe^i%1I8%!k}dW~^A3oUdVbr@xN=W*z;oM)&mOH9AJ; z?V-D0ZCtWv_V0e<^DYPTj5Rf8pEA9_;lTNW$8*{BesfE>HAd`tKBxGCC3%Ut%$YS^ k!c;T$_%BR#x)r^n-y|50bQb$W#~>$h&d6*lfA+8ZZz&gi0ssI2 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Hedgehog.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Hedgehog.set new file mode 100644 index 0000000000000000000000000000000000000000..c543a3fbd1081f7a7d24929c8f3f4ad96c0a86ff GIT binary patch literal 692 zcma))K}*9>5QOI}_#blfqEbOm(vu(vdKG)D@mYg52~8?0{&w}7eI`~sR7zj=?e5IZ zPV)J2szTRFTB%c|Mm6_F_ndpW(p_(_xCHYSxCPm5$_lt%K$^`n=DO1}=q^}) zv^Lb%v4b_a)5`J|R^E}bwjQR1UZavCYvz6KB|BD}kHnX-d(vM=f3psLSfgip^BNt4 z^Y+lwFGiQ_nf<#Rect9^-mwN__9@%@9j=Mr`FSt9-jBD0TSLX3=Qzb1Ea^+^WzMYW l9HyGBhi_r3MVB}TVIt)+{OD=_bYTN2%+tbpqkq}kkKp?kf6?t}G5 zYfEm78LY{bR+gu*@}8Kr4KOYB7MT=LGaquVn6YMk;(P_WJN9?xahhs`bF)|9d5`JCblR@5ctGH2Fw l0aL@&)4wp&=~niZeq}Hm=_K}2$3#l1%$sBLEyVnvh;I&Wd|m(m literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Josephine.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Josephine.set new file mode 100644 index 0000000000000000000000000000000000000000..8d82f2c93b358d470bbb34c2249e8beeb652b601 GIT binary patch literal 688 zcma))K}*9>5QOI}_#blfqM#nUNKb+w=vC~o#%B%MBs7Vr_}kTQ_K~#Wp;G#?Z+B;Q zc9QR}a}~N((psG=HLAHcdgMINjTY+lqzj%eDm8FAllwY43Q&nmp?&SiT<)*P7I0Mb zC!#WVd$1M!uKC%*XJku$&3_e4S&7jNS!-!y;tI@1;Fe@}DJ$T518FwTSm;5opu1q* zXlg|GH2Fw j2~*A1tR~xEg~sUGaqsA*XS6X zw}J{Mo?B{G=PGooq_sL#YE*M?^vHUk8_m`0Nf+$TDmAbg$$1?a1yu>8(7yI$F6URE1soOm ziBlQ8J+&45j(Kn4b7c#@=3NC-R^sXg)LPo;xT5Ag>K358lofEjQfW5#nCn3=RCmGp zqqQM6#0=KtOe@P%Sa}C#Z9Pm2y+tGiYUV@kB{Np6OU~D@yVGAsf3uE$SfhJ-@){kZ z^Y+l)uQo2(Gy8YH@p+endB&O=vrn1c-*Djk!Q;8?dcV0P+!`bHJfBm1!IHehT;|N0 lE@7&fdi)orI@^lg(QgtAM>>stqGOPgIA>(Gl|TDe{x>PFd;kCd literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Sink.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Sink.set new file mode 100644 index 0000000000000000000000000000000000000000..4da1d77a9126b447ca5d524190c4a4ce72c4591b GIT binary patch literal 686 zcma))PfNp45X9#!_#JZdqSE3~dJ+UduVRliK5MW|N|T6+pI!aUJ`yV)Dk1OB?C$LB zBwwHBDs-!)ty)!TRC90i$aRFBCyq1iDssvK#PzN%X^DEE-j*9%m zsSMtZ+6sQhyl>!h1X2rP=CbucaU7LgRFnUA@b%viBLbH0Y%o&Gxdn|1KR8r{>A*XS6W zw}QpHqCnlDx!R=FFNd lVXB#W_!nlHYO)i*qvIqvPIMOgM5iFrIA>(OlRy7g{x=hhd@29{ literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/Examples/Math 3D/Sets/Skin.set b/BKPS/14031218/Experts/Examples/Math 3D/Sets/Skin.set new file mode 100644 index 0000000000000000000000000000000000000000..4d2bf73aa7a781c4a88d52b4f57437665b072360 GIT binary patch literal 686 zcma))PfNp45X9#!_#JZdqEZD<(vu(vdKG)D@mWJ{5}HI*{Osy)_K{ZcPziZ|W_M?2 zC;9q3SD{-at<|Ygqndl8N7e(~Xs%vQx?q1+se#o<&g;l1s7fG(_O&N-Illre;Hbz? zoXX(ssjc95%zF!;D_ih2?<$zG5?42%*3w4D6*ccsw*cLxtbps4O0&7gTn~Dox(n8= z)`r*+Ggy-|tt?MrPJbQ!%{uyFjqd5mYjljx z+e3H1+PGxT?BD&y=Uoow8Eb0HK4p4;!-4Y$kLR-M{pOZ%YmC_Qd`|HNOY#zPnKNs; lgsEog@n4wggl8MSqvIqvj&v6LM8_bfan8u>NB-tR~zEg~sUGaqs + +input double MaximumRisk = 0.02; // Maximum Risk in percentage +input double DecreaseFactor = 3; // Descrease factor +input int MovingPeriod = 12; // Moving Average period +input int MovingShift = 6; // Moving Average shift +//--- +int ExtHandle=0; +bool ExtHedging=false; +CTrade ExtTrade; + +#define MA_MAGIC 1234501 +//+------------------------------------------------------------------+ +//| Calculate optimal lot size | +//+------------------------------------------------------------------+ +double TradeSizeOptimized(void) + { + double price=0.0; + double margin=0.0; +//--- select lot size + if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price)) + return(0.0); + if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin)) + return(0.0); + if(margin<=0.0) + return(0.0); + + double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2); +//--- calculate number of losses orders without a break + if(DecreaseFactor>0) + { + //--- select history for access + HistorySelect(0,TimeCurrent()); + //--- + int orders=HistoryDealsTotal(); // total history deals + int losses=0; // number of losses orders without a break + + for(int i=orders-1;i>=0;i--) + { + ulong ticket=HistoryDealGetTicket(i); + if(ticket==0) + { + Print("HistoryDealGetTicket failed, no trade history"); + break; + } + //--- check symbol + if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol) + continue; + //--- check Expert Magic number + if(HistoryDealGetInteger(ticket,DEAL_MAGIC)!=MA_MAGIC) + continue; + //--- check profit + double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); + if(profit>0.0) + break; + if(profit<0.0) + losses++; + } + //--- + if(losses>1) + lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1); + } +//--- normalize and check limits + double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); + lot=stepvol*NormalizeDouble(lot/stepvol,0); + + double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); + if(lotmaxvol) + lot=maxvol; +//--- return trading volume + return(lot); + } +//+------------------------------------------------------------------+ +//| Check for open position conditions | +//+------------------------------------------------------------------+ +void CheckForOpen(void) + { + MqlRates rt[2]; +//--- go trading only for first ticks of new bar + if(CopyRates(_Symbol,_Period,0,2,rt)!=2) + { + Print("CopyRates of ",_Symbol," failed, no history"); + return; + } + if(rt[1].tick_volume>1) + return; +//--- get current Moving Average + double ma[1]; + if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) + { + Print("CopyBuffer from iMA failed, no data"); + return; + } +//--- check signals + ENUM_ORDER_TYPE signal=WRONG_VALUE; + + if(rt[0].open>ma[0] && rt[0].closema[0]) + signal=ORDER_TYPE_BUY; // buy conditions + } +//--- additional checking + if(signal!=WRONG_VALUE) + { + if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100) + ExtTrade.PositionOpen(_Symbol,signal,TradeSizeOptimized(), + SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK), + 0,0); + } +//--- + } +//+------------------------------------------------------------------+ +//| Check for close position conditions | +//+------------------------------------------------------------------+ +void CheckForClose(void) + { + MqlRates rt[2]; +//--- go trading only for first ticks of new bar + if(CopyRates(_Symbol,_Period,0,2,rt)!=2) + { + Print("CopyRates of ",_Symbol," failed, no history"); + return; + } + if(rt[1].tick_volume>1) + return; +//--- get current Moving Average + double ma[1]; + if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) + { + Print("CopyBuffer from iMA failed, no data"); + return; + } +//--- positions already selected before + bool signal=false; + long type=PositionGetInteger(POSITION_TYPE); + + if(type==(long)POSITION_TYPE_BUY && rt[0].open>ma[0] && rt[0].closema[0]) + signal=true; +//--- additional checking + if(signal) + { + if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100) + ExtTrade.PositionClose(_Symbol,3); + } +//--- + } +//+------------------------------------------------------------------+ +//| Position select depending on netting or hedging | +//+------------------------------------------------------------------+ +bool SelectPosition() + { + bool res=false; +//--- check position in Hedging mode + if(ExtHedging) + { + uint total=PositionsTotal(); + for(uint i=0; i +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=120100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long black + (Open(2)-Close(2)>AvgBody(1)) && + (Open(1)-Close(1)>AvgBody(1)) && + (MidPoint(2)AvgBody(1)) && // long white + (Close(2)-Open(2)>AvgBody(1)) && + (Close(1)-Open(1)>AvgBody(1)) && + (MidPoint(2)>MidPoint(3)) && // higher midpoints + (MidPoint(1)>MidPoint(2))) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\n3 White Soldiers detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=CCI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<-50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI<-50"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers MFI.mq5 b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers MFI.mq5 new file mode 100644 index 0000000..e9bb791 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers MFI.mq5 @@ -0,0 +1,657 @@ +//+------------------------------------------------------------------+ +//| BlackCrows WhiteSoldiers MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=120200; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long black + (Open(2)-Close(2)>AvgBody(1)) && + (Open(1)-Close(1)>AvgBody(1)) && + (MidPoint(2)AvgBody(1)) && // long white + (Close(2)-Open(2)>AvgBody(1)) && + (Close(1)-Open(1)>AvgBody(1)) && + (MidPoint(2)>MidPoint(3)) && // higher midpoints + (MidPoint(1)>MidPoint(2))) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\n3 White Soldiers detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=MFI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers RSI.mq5 b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers RSI.mq5 new file mode 100644 index 0000000..c79c357 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers RSI.mq5 @@ -0,0 +1,657 @@ +//+------------------------------------------------------------------+ +//| BlackCrows WhiteSoldiers RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=120300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long black + (Open(2)-Close(2)>AvgBody(1)) && + (Open(1)-Close(1)>AvgBody(1)) && + (MidPoint(2)AvgBody(1)) && // long white + (Close(2)-Open(2)>AvgBody(1)) && + (Close(1)-Open(1)>AvgBody(1)) && + (MidPoint(2)>MidPoint(3)) && // higher midpoints + (MidPoint(1)>MidPoint(2))) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\n3 White Soldiers detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=RSI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers Stoch.mq5 new file mode 100644 index 0000000..81ed611 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BlackCrows WhiteSoldiers Stoch.mq5 @@ -0,0 +1,661 @@ +//+------------------------------------------------------------------+ +//| BlackCrows WhiteSoldiers Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=120400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long black + (Open(2)-Close(2)>AvgBody(1)) && + (Open(1)-Close(1)>AvgBody(1)) && + (MidPoint(2)AvgBody(1)) && // long white + (Close(2)-Open(2)>AvgBody(1)) && + (Close(1)-Open(1)>AvgBody(1)) && + (MidPoint(2)>MidPoint(3)) && // higher midpoints + (MidPoint(1)>MidPoint(2))) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\n3 White Soldiers detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=StochSignal(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<30)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal<30"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing CCI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing CCI.mq5 new file mode 100644 index 0000000..b8347bc --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing CCI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Engulfing CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=121100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // body of the candle is higher than average value of the body + (Close(1)CloseAvg(2)) && // uptrend + (Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Engulfing detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Engulfing + if((Open(2)>Close(2)) && // previous candle is bearish + (Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body + (Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle + (MidOpenClose(2)50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing MFI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing MFI.mq5 new file mode 100644 index 0000000..ef447bb --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing MFI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Engulfing MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=120600; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // body of the candle is higher than average value of the body + (Close(1)CloseAvg(2)) && // uptrend + (Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Engulfing detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Engulfing + if((Open(2)>Close(2)) && // previous candle is bearish + (Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body + (Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle + (MidOpenClose(2)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing RSI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing RSI.mq5 new file mode 100644 index 0000000..7524628 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing RSI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Engulfing RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=121300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // body of the candle is higher than average value of the body + (Close(1)CloseAvg(2)) && // uptrend + (Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Engulfing detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Engulfing + if((Open(2)>Close(2)) && // previous candle is bearish + (Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body + (Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle + (MidOpenClose(2)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing Stoch.mq5 new file mode 100644 index 0000000..7437be3 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Engulfing Stoch.mq5 @@ -0,0 +1,688 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Engulfing Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow=13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=121400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } + +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // body of the candle is higher than average value of the body + (Close(1)CloseAvg(2)) && // uptrend + (Open(1)>Close(2))) // Open price of the bearish candle is higher than close price of the bullish candle + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Engulfing detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Engulfing + if((Open(2)>Close(2)) && // previous candle is bearish + (Close(1)-Open(1)>AvgBody(1)) && // body of the bullish candle is higher than average value of the body + (Close(1)>Open(2)) && // close price of the bullish candle is higher than open price of the bearish candle + (MidOpenClose(2)70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Harami CCI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami CCI.mq5 new file mode 100644 index 0000000..b61b438 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami CCI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Harami CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=122100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white) + (Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle + (Open(1)CloseAvg(2))) // up trend + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Harami detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Harami + if((Close(1)>Open(1)) && // the last completed bar is bullish (white day) + ((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black) + (Close(1)Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle + (MidPoint(2)50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Harami MFI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami MFI.mq5 new file mode 100644 index 0000000..ff639f8 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami MFI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Harami MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=121600; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white) + (Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle + (Open(1)CloseAvg(2))) // up trend + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Harami detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Harami + if((Close(1)>Open(1)) && // the last completed bar is bullish (white day) + ((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black) + (Close(1)Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle + (MidPoint(2)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Harami RSI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami RSI.mq5 new file mode 100644 index 0000000..cf4082a --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami RSI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Harami RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=121300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white) + (Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle + (Open(1)CloseAvg(2))) // up trend + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Harami detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Harami + if((Close(1)>Open(1)) && // the last completed bar is bullish (white day) + ((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black) + (Close(1)Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle + (MidPoint(2)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish Harami Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami Stoch.mq5 new file mode 100644 index 0000000..10c4b8a --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish Harami Stoch.mq5 @@ -0,0 +1,685 @@ +//+------------------------------------------------------------------+ +//| BullishBearish Harami Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=122400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle =INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } +//--- open position not found + return(false); + } + +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // the previous candle is bullish, its body is greater than average (long white) + (Close(1)>Open(2)) && // close price of the bearish candle is higher than open price of the bullish candle + (Open(1)CloseAvg(2))) // up trend + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish Harami detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish Harami + if((Close(1)>Open(1)) && // the last completed bar is bullish (white day) + ((Open(2)-Close(2))>AvgBody(1)) && // the previous candle is bearish, its body is greater than average (long black) + (Close(1)Close(2)) && // open price of the bullish candle is higher than close price of the bearish candle + (MidPoint(2)70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines CCI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines CCI.mq5 new file mode 100644 index 0000000..761f926 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines CCI.mq5 @@ -0,0 +1,654 @@ +//+------------------------------------------------------------------+ +//| BullishBearish MeetingLines CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=123100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error + +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long white candle + ((Open(1)-Close(1))>AvgBody(1)) && // long black candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish MeetingLines detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish MeetingLines + if((Open(2)-Close(2)>AvgBody(1)) && // long black candle + ((Close(1)-Open(1))>AvgBody(1)) && // long white candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nBullish MeetingLines detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } + +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=CCI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<-50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI<-50"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines MFI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines MFI.mq5 new file mode 100644 index 0000000..375c13d --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines MFI.mq5 @@ -0,0 +1,652 @@ +//+------------------------------------------------------------------+ +//| BullishBearish MeetingLines MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=121200; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long white candle + ((Open(1)-Close(1))>AvgBody(1)) && // long black candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish MeetingLines detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish MeetingLines + if((Open(2)-Close(2)>AvgBody(1)) && // long black candle + ((Close(1)-Open(1))>AvgBody(1)) && // long white candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nBullish MeetingLines detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=MFI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines RSI.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines RSI.mq5 new file mode 100644 index 0000000..76a9be9 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines RSI.mq5 @@ -0,0 +1,653 @@ +//+------------------------------------------------------------------+ +//| BullishBearish MeetingLines RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot =0.1; // lot +//--- Expert ID +input long InpMagicNumber=122300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } + +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long white candle + ((Open(1)-Close(1))>AvgBody(1)) && // long black candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nBearish MeetingLines detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Bullish MeetingLines + if((Open(2)-Close(2)>AvgBody(1)) && // long black candle + ((Close(1)-Open(1))>AvgBody(1)) && // long white candle + (MathAbs(Close(1)-Close(2))<0.1*AvgBody(1))) // doji close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nBullish MeetingLines detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=RSI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines Stoch.mq5 new file mode 100644 index 0000000..de4acc7 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/BullishBearish MeetingLines Stoch.mq5 @@ -0,0 +1,662 @@ +//+------------------------------------------------------------------+ +//| BullishBearish MeetingLines Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=123400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen=0; // Buy/Sell signal +int ExtSignalClose=0; // signal to close a position +string ExtPatternInfo=""; // current pattern information +string ExtDirection=""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed=false; // pattern confirmed +bool ExtCloseByTime=true; // requires closing by time +bool ExtCheckPassed=true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } + +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long black + (Open(2)-Close(2)>AvgBody(1)) && + (Open(1)-Close(1)>AvgBody(1)) && + (MidPoint(2)AvgBody(1)) && // long white + (Close(2)-Open(2)>AvgBody(1)) && + (Close(1)-Open(1)>AvgBody(1)) && + (MidPoint(2)>MidPoint(3)) && // higher midpoints + (MidPoint(1)>MidPoint(2))) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\n3 White Soldiers detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=StochSignal(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<30)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal<30"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine CCI.mq5 b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine CCI.mq5 new file mode 100644 index 0000000..4f87e86 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine CCI.mq5 @@ -0,0 +1,682 @@ +//+------------------------------------------------------------------+ +//| DarkCloud PiercingLine CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=120500; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long body of the white candlestick (long white) + (Close(1)Open(2)) && // close within the previous candlestick body (white) + (MidOpenClose(2)>CloseAvg(2)) && // uptrend + (Open(1)>High(2))) // open above the previous day's High price (open at new high) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nDark Cloud Cover detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Piercing Line + if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white) + (Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black) + (Close(1)>Close(2)) && // close within the body + (Close(1)50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine MFI.mq5 b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine MFI.mq5 new file mode 100644 index 0000000..b739422 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine MFI.mq5 @@ -0,0 +1,681 @@ +//+------------------------------------------------------------------+ +//| DarkCloud PiercingLine MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=122600; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long body of the white candlestick (long white) + (Close(1)Open(2)) && // close within the previous candlestick body (white) + (MidOpenClose(2)>CloseAvg(2)) && // uptrend + (Open(1)>High(2))) // open above the previous day's High price (open at new high) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nDark Cloud Cover detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Piercing Line + if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white) + (Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black) + (Close(1)>Close(2)) && // close within the body + (Close(1)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine RSI.mq5 b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine RSI.mq5 new file mode 100644 index 0000000..4a83bb3 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine RSI.mq5 @@ -0,0 +1,683 @@ +//+------------------------------------------------------------------+ +//| DarkCloud PiercingLine RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=120700; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long body of the white candlestick (long white) + (Close(1)Open(2)) && // close within the previous candlestick body (white) + (MidOpenClose(2)>CloseAvg(2)) && // uptrend + (Open(1)>High(2))) // open above the previous day's High price (open at new high) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nDark Cloud Cover detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Piercing Line + if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white) + (Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black) + (Close(1)>Close(2)) && // close within the body + (Close(1)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine Stoch.mq5 new file mode 100644 index 0000000..4eb1a89 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/DarkCloud PiercingLine Stoch.mq5 @@ -0,0 +1,687 @@ +//+------------------------------------------------------------------+ +//| DarkCloud PiercingLine Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=120800; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // long body of the white candlestick (long white) + (Close(1)Open(2)) && // close within the previous candlestick body (white) + (MidOpenClose(2)>CloseAvg(2)) && // uptrend + (Open(1)>High(2))) // open above the previous day's High price (open at new high) + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nDark Cloud Cover detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Piercing Line + if((Close(1)-Open(1)>AvgBody(1)) && // long body of the white candlestick (long white) + (Open(2)-Close(2)>AvgBody(1)) && // long body of the previous black candlestick (long black) + (Close(1)>Close(2)) && // close within the body + (Close(1)70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/HangingMan Hammer CCI.mq5 b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer CCI.mq5 new file mode 100644 index 0000000..d137f14 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer CCI.mq5 @@ -0,0 +1,679 @@ +//+------------------------------------------------------------------+ +//| HangingMan Hammer CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=124100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeCloseAvg(2)) && // up trend + (MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nHanging Man detected"; + ExtDirection="Sell"; + return(true); + } + + +//--- check Hammer + if((MidPoint(1)(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/HangingMan Hammer MFI.mq5 b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer MFI.mq5 new file mode 100644 index 0000000..94428f1 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer MFI.mq5 @@ -0,0 +1,679 @@ +//+------------------------------------------------------------------+ +//| HangingMan Hammer MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=123600; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } + +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeCloseAvg(2)) && // up trend + (MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nHanging Man detected"; + ExtDirection="Sell"; + return(true); + } + + +//--- check Hammer + if((MidPoint(1)(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/HangingMan Hammer RSI.mq5 b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer RSI.mq5 new file mode 100644 index 0000000..3ee08ba --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer RSI.mq5 @@ -0,0 +1,677 @@ +//+------------------------------------------------------------------+ +//| HangingMan Hammer RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=123300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeCloseAvg(2)) && // up trend + (MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nHanging Man detected"; + ExtDirection="Sell"; + return(true); + } + +//--- check Hammer + if((MidPoint(1)(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/HangingMan Hammer Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer Stoch.mq5 new file mode 100644 index 0000000..d64b8e0 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/HangingMan Hammer Stoch.mq5 @@ -0,0 +1,683 @@ +//+------------------------------------------------------------------+ +//| HangingMan Hammer Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpMAPeriod =5; // Trend MA period +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied=STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=124400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handles +int ExtIndicatorHandle=INVALID_HANDLE; +int ExtTrendMAHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } + +//--- trend moving average + ExtTrendMAHandle=iMA(_Symbol, _Period, InpMAPeriod,0, MODE_SMA,PRICE_CLOSE); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating Moving Average indicator"); + return(INIT_FAILED); + } + +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeCloseAvg(2)) && // up trend + (MathMin(Open(1), Close(1))> (High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)>Close(2)) && (Open(1)>Open(2))) // body gap + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_SELL; + ExtPatternInfo="\r\nHanging Man detected"; + ExtDirection="Sell"; + return(true); + } + + +//--- check Hammer + if((MidPoint(1)(High(1)-(High(1)-Low(1))/3.0)) && // body in upper 1/3 + (Close(1)70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ +//| SMA value at the specified bar | +//+------------------------------------------------------------------+ +double CloseAvg(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtTrendMAHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the Simple Moving Average indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji CCI.mq5 b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji CCI.mq5 new file mode 100644 index 0000000..c6338a1 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji CCI.mq5 @@ -0,0 +1,685 @@ +//+------------------------------------------------------------------+ +//| MorningEvening StarDoji CCI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodCCI =37; // CCI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration =10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage =10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=130100; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iCCI(_Symbol, _Period, InpPeriodCCI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Open(1)AvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Close(1)AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(2)) && // upward price gap on the last candlestick + (Close(1)>Close(2))) // last candlestick close higher than second candlestick close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Doji detected"; + ExtDirection="Buy"; + return(true); + } + +//--- check Morning Star + if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Star detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=CCI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<-50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI<-50"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>50)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: CCI>50"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((CCI(1)<80) && (CCI(2)>80)) || ((CCI(1)<-80) && (CCI(2)>-80))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((CCI(1)>-80) && (CCI(2)<-80)) || ((CCI(1)>80) && (CCI(2)<80))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| CCI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double CCI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the CCI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji MFI.mq5 b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji MFI.mq5 new file mode 100644 index 0000000..0771bc5 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji MFI.mq5 @@ -0,0 +1,686 @@ +//+------------------------------------------------------------------+ +//| MorningEvening StarDoji MFI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodMFI =37; // MFI period +input ENUM_APPLIED_VOLUME InpVolume=VOLUME_TICK; // volume type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=130200; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iMFI(_Symbol, _Period, InpPeriodMFI, InpVolume); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating MFI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Open(1)AvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Close(1)AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(2)) && // upward price gap on the last candlestick + (Close(1)>Close(2))) // last candlestick close higher than second candlestick close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Doji detected"; + ExtDirection="Buy"; + return(true); + } + +//--- check Morning Star + if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Star detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=MFI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: MFI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((MFI(1)<70) && (MFI(2)>70)) || ((MFI(1)<30) && (MFI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((MFI(1)>30) && (MFI(2)<30)) || ((MFI(1)>70) && (MFI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| MFI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double MFI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the MFI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji RSI.mq5 b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji RSI.mq5 new file mode 100644 index 0000000..293d897 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji RSI.mq5 @@ -0,0 +1,686 @@ +//+------------------------------------------------------------------+ +//| MorningEvening StarDoji RSI.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpPeriodRSI =37; // RSI period +input ENUM_APPLIED_PRICE InpPrice=PRICE_CLOSE; // price type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=130300; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iRSI(_Symbol, _Period, InpPeriodRSI, InpPrice); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating CCI indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Open(1)AvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Close(1)AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(2)) && // upward price gap on the last candlestick + (Close(1)>Close(2))) // last candlestick close higher than second candlestick close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Doji detected"; + ExtDirection="Buy"; + return(true); + } + +//--- check Morning Star + if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Star detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=RSI(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<40)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI<40"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>60)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: RSI>60"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((RSI(1)<70) && (RSI(2)>70)) || ((RSI(1)<30) && (RSI(2)>30))) + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if(((RSI(1)>30) && (RSI(2)<30)) || ((RSI(1)>70) && (RSI(2)<70))) + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| RSI indicator value at the specified bar | +//+------------------------------------------------------------------+ +double RSI(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, 0, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the RSI indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji Stoch.mq5 b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji Stoch.mq5 new file mode 100644 index 0000000..8a58965 --- /dev/null +++ b/BKPS/14031218/Experts/Free Robots/MorningEvening StarDoji Stoch.mq5 @@ -0,0 +1,691 @@ +//+------------------------------------------------------------------+ +//| MorningEvening StarDoji Stoch.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include + +#define SIGNAL_BUY 1 // Buy signal +#define SIGNAL_NOT 0 // no trading signal +#define SIGNAL_SELL -1 // Sell signal + +#define CLOSE_LONG 2 // signal to close Long +#define CLOSE_SHORT -2 // signal to close Short + +//--- Input parameters +input int InpAverBodyPeriod=12; // period for calculating average candlestick size +input int InpStochK =47; // period %K +input int InpStochD =9; // period %D +input int InpStochSlow =13; // smoothing period %K +input ENUM_STO_PRICE InpStochApplied =STO_LOWHIGH; // calculation type +input ENUM_MA_METHOD InpStochMA =MODE_SMA; // smoothing type + +//--- trade parameters +input uint InpDuration=10; // position holding time in bars +input uint InpSL =200; // Stop Loss in points +input uint InpTP =200; // Take Profit in points +input uint InpSlippage=10; // slippage in points +//--- money management parameters +input double InpLot=0.1; // lot +//--- Expert ID +input long InpMagicNumber=130400; // Magic Number + +//--- global variables +int ExtAvgBodyPeriod; // average candlestick calculation period +int ExtSignalOpen =0; // Buy/Sell signal +int ExtSignalClose =0; // signal to close a position +string ExtPatternInfo =""; // current pattern information +string ExtDirection =""; // position opening direction +bool ExtPatternDetected=false; // pattern detected +bool ExtConfirmed =false; // pattern confirmed +bool ExtCloseByTime =true; // requires closing by time +bool ExtCheckPassed =true; // status checking error +//--- indicator handle +int ExtIndicatorHandle=INVALID_HANDLE; + +//--- service objects +CTrade ExtTrade; +CSymbolInfo ExtSymbolInfo; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + Print("InpSL=", InpSL); + Print("InpTP=", InpTP); +//--- set parameters for trading operations + ExtTrade.SetDeviationInPoints(InpSlippage); // slippage + ExtTrade.SetExpertMagicNumber(InpMagicNumber); // Expert Advisor ID + ExtTrade.LogLevel(LOG_LEVEL_ERRORS); // logging level + + ExtAvgBodyPeriod=InpAverBodyPeriod; +//--- indicator initialization + ExtIndicatorHandle=iStochastic(_Symbol, _Period, InpStochK, InpStochD, InpStochSlow, InpStochMA, InpStochApplied); + if(ExtIndicatorHandle==INVALID_HANDLE) + { + Print("Error creating iStochastic indicator"); + return(INIT_FAILED); + } +//--- OK + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- release indicator handle + IndicatorRelease(ExtIndicatorHandle); + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- save the next bar start time; all checks at bar opening only + static datetime next_bar_open=0; + +//--- Phase 1 - check the emergence of a new bar and update the status + if(TimeCurrent()>=next_bar_open) + { + //--- get the current state of environment on the new bar + // namely, set the values of global variables: + // ExtPatternDetected - pattern detection + // ExtConfirmed - pattern confirmation + // ExtSignalOpen - signal to open + // ExtSignalClose - signal to close + // ExtPatternInfo - current pattern information + if(CheckState()) + { + //--- set the new bar opening time + next_bar_open=TimeCurrent(); + next_bar_open-=next_bar_open%PeriodSeconds(_Period); + next_bar_open+=PeriodSeconds(_Period); + + //--- report the emergence of a new bar only once within a bar + if(ExtPatternDetected && ExtConfirmed) + Print(ExtPatternInfo); + } + else + { + //--- error getting the status, retry on the next tick + return; + } + } + +//--- Phase 2 - if there is a signal and no position in this direction + if(ExtSignalOpen && !PositionExist(ExtSignalOpen)) + { + Print("\r\nSignal to open position ", ExtDirection); + PositionOpen(); + if(PositionExist(ExtSignalOpen)) + ExtSignalOpen=SIGNAL_NOT; + } + +//--- Phase 3 - close if there is a signal to close + if(ExtSignalClose && PositionExist(ExtSignalClose)) + { + Print("\r\nSignal to close position ", ExtDirection); + CloseBySignal(ExtSignalClose); + if(!PositionExist(ExtSignalClose)) + ExtSignalClose=SIGNAL_NOT; + } + +//--- Phase 4 - close upon expiration + if(ExtCloseByTime && PositionExpiredByTimeExist()) + { + CloseByTime(); + ExtCloseByTime=PositionExpiredByTimeExist(); + } + } +//+------------------------------------------------------------------+ +//| Get the current environment and check for a pattern | +//+------------------------------------------------------------------+ +bool CheckState() + { +//--- check if there is a pattern + if(!CheckPattern()) + { + Print("Error, failed to check pattern"); + return(false); + } + +//--- check for confirmation + if(!CheckConfirmation()) + { + Print("Error, failed to check pattern confirmation"); + return(false); + } +//--- if there is no confirmation, cancel the signal + if(!ExtConfirmed) + ExtSignalOpen=SIGNAL_NOT; + +//--- check if there is a signal to close a position + if(!CheckCloseSignal()) + { + Print("Error, failed to check the closing signal"); + return(false); + } + +//--- if positions are to be closed after certain holding time in bars + if(InpDuration) + ExtCloseByTime=true; // set flag to close upon expiration + +//--- all checks done + return(true); + } +//+------------------------------------------------------------------+ +//| Open a position in the direction of the signal | +//+------------------------------------------------------------------+ +bool PositionOpen() + { + ExtSymbolInfo.Refresh(); + ExtSymbolInfo.RefreshRates(); + + double price=0; +//--- Stop Loss and Take Profit are not set by default + double stoploss=0.0; + double takeprofit=0.0; + + int digits=ExtSymbolInfo.Digits(); + double point=ExtSymbolInfo.Point(); + double spread=ExtSymbolInfo.Ask()-ExtSymbolInfo.Bid(); + +//--- uptrend + if(ExtSignalOpen==SIGNAL_BUY) + { + price=NormalizeDouble(ExtSymbolInfo.Ask(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price-spread, digits); + } + else + stoploss = NormalizeDouble(price-InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price+spread, digits); + } + else + takeprofit = NormalizeDouble(price+InpTP*point, digits); + } + + if(!ExtTrade.Buy(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s buy %G at %G (sl=%G tp=%G) failed. Ask=%G error=%d", + Symbol(), InpLot, price, stoploss, takeprofit, ExtSymbolInfo.Ask(), GetLastError()); + return(false); + } + } + +//--- downtrend + if(ExtSignalOpen==SIGNAL_SELL) + { + price=NormalizeDouble(ExtSymbolInfo.Bid(), digits); + //--- if Stop Loss is set + if(InpSL>0) + { + if(spread>=InpSL*point) + { + PrintFormat("StopLoss (%d points) <= current spread = %.0f points. Spread value will be used", InpSL, spread/point); + stoploss = NormalizeDouble(price+spread, digits); + } + else + stoploss = NormalizeDouble(price+InpSL*point, digits); + } + //--- if Take Profit is set + if(InpTP>0) + { + if(spread>=InpTP*point) + { + PrintFormat("TakeProfit (%d points) < current spread = %.0f points. Spread value will be used", InpTP, spread/point); + takeprofit = NormalizeDouble(price-spread, digits); + } + else + takeprofit = NormalizeDouble(price-InpTP*point, digits); + } + + if(!ExtTrade.Sell(InpLot, Symbol(), price, stoploss, takeprofit)) + { + PrintFormat("Failed %s sell at %G (sl=%G tp=%G) failed. Bid=%G error=%d", + Symbol(), price, stoploss, takeprofit, ExtSymbolInfo.Bid(), GetLastError()); + ExtTrade.PrintResult(); + Print(" "); + return(false); + } + } + + return(true); + } +//+------------------------------------------------------------------+ +//| Close a position based on the specified signal | +//+------------------------------------------------------------------+ +void CloseBySignal(int type_close) + { +//--- if there is no signal to close, return successful completion + if(type_close==SIGNAL_NOT) + return; +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalClose)==0) + return; + +//--- closing direction + long type; + switch(type_close) + { + case CLOSE_SHORT: + type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + type=POSITION_TYPE_BUY; + break; + default: + Print("Error! Signal to close not detected"); + return; + } + +//--- check all positions and close ours based on the signal + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + if(PositionGetInteger(POSITION_TYPE)==type) + { + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Close positions upon holding time expiration in bars | +//+------------------------------------------------------------------+ +void CloseByTime() + { +//--- if there are no positions opened by our EA + if(PositionExist(ExtSignalOpen)==0) + return; + +//--- check all positions and close ours based on the holding time in bars + int positions=PositionsTotal(); + for(int i=positions-1; i>=0; i--) + { + ulong ticket=PositionGetTicket(i); + if(ticket!=0) + { + //--- get the name of the symbol and the position id (magic) + string symbol=PositionGetString(POSITION_SYMBOL); + long magic =PositionGetInteger(POSITION_MAGIC); + //--- if they correspond to our values + if(symbol==Symbol() && magic==InpMagicNumber) + { + //--- position opening time + datetime open_time=(datetime)PositionGetInteger(POSITION_TIME); + //--- check position holding time in bars + if(BarsHold(open_time)>=(int)InpDuration) + { + Print("\r\nTime to close position #", ticket); + ExtTrade.PositionClose(ticket, InpSlippage); + ExtTrade.PrintResult(); + Print(" "); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Returns true if there are open positions | +//+------------------------------------------------------------------+ +bool PositionExist(int signal_direction) + { + bool check_type=(signal_direction!=SIGNAL_NOT); + +//--- what positions to search + ENUM_POSITION_TYPE search_type=WRONG_VALUE; + if(check_type) + switch(signal_direction) + { + case SIGNAL_BUY: + search_type=POSITION_TYPE_BUY; + break; + case SIGNAL_SELL: + search_type=POSITION_TYPE_SELL; + break; + case CLOSE_LONG: + search_type=POSITION_TYPE_BUY; + break; + case CLOSE_SHORT: + search_type=POSITION_TYPE_SELL; + break; + default: + //--- entry direction is not specified; nothing to search + return(false); + } + +//--- go through the list of all positions + int positions=PositionsTotal(); + for(int i=0; i=(int)InpDuration)) + return(true); + } + } + } + +//--- open position not found + return(false); + } +//+------------------------------------------------------------------+ +//| Checks position closing time in bars | +//+------------------------------------------------------------------+ +int BarsHold(datetime open_time) + { +//--- first run a basic simple check + if(TimeCurrent()-open_timeAvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Open(1)AvgBody(1)) && // bullish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(3)) && // second candlestick close is higher than first candlestick close + (Open(2)>Open(3)) && // second candlestick open is higher than first candlestick open + (Close(1)AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))Close(2)) && // upward price gap on the last candlestick + (Close(1)>Close(2))) // last candlestick close higher than second candlestick close + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Doji detected"; + ExtDirection="Buy"; + return(true); + } + +//--- check Morning Star + if((Open(3)-Close(3)>AvgBody(1)) && // bearish candlestick, its body is larger than average + (MathAbs(Close(2)-Open(2))MidOpenClose(3))) // last candlestick close is lower than the middle of the first (bearish) one + { + ExtPatternDetected=true; + ExtSignalOpen=SIGNAL_BUY; + ExtPatternInfo="\r\nMorning Star detected"; + ExtDirection="Buy"; + return(true); + } + +//--- result of checking + return(ExtCheckPassed); + } +//+------------------------------------------------------------------+ +//| Returns true in case of successful confirmation check | +//+------------------------------------------------------------------+ +bool CheckConfirmation() + { + ExtConfirmed=false; +//--- if there is no pattern, do not search for confirmation + if(!ExtPatternDetected) + return(true); + +//--- get the value of the stochastic indicator to confirm the signal + double signal=StochSignal(1); + if(signal==EMPTY_VALUE) + { + //--- failed to get indicator value, check failed + return(false); + } + +//--- check the Buy signal + if(ExtSignalOpen==SIGNAL_BUY && (signal<30)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal<30"; + } + +//--- check the Sell signal + if(ExtSignalOpen==SIGNAL_SELL && (signal>70)) + { + ExtConfirmed=true; + ExtPatternInfo+="\r\n Confirmed: StochSignal>70"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Check if there is a signal to close | +//+------------------------------------------------------------------+ +bool CheckCloseSignal() + { + ExtSignalClose=false; +//--- if there is a signal to enter the market, do not check the signal to close + if(ExtSignalOpen!=SIGNAL_NOT) + return(true); + +//--- check if there is a signal to close a long position + if(((StochSignal(1)<80) && (StochSignal(2)>80))|| // 80 crossed downwards + ((StochSignal(1)<20) && (StochSignal(2)>20))) // 20 crossed downwards + { + //--- there is a signal to close a long position + ExtSignalClose=CLOSE_LONG; + ExtDirection="Long"; + } + +//--- check if there is a signal to close a short position + if((((StochSignal(1)>20) && (StochSignal(2)<20)) || // 20 crossed upwards + ((StochSignal(1)>80) && (StochSignal(2)<80)))) // 80 crossed upwards + { + //--- there is a signal to close a short position + ExtSignalClose=CLOSE_SHORT; + ExtDirection="Short"; + } + +//--- successful completion of the check + return(true); + } +//+------------------------------------------------------------------+ +//| Stochastic indicator value at the specified bar | +//+------------------------------------------------------------------+ +double StochSignal(int index) + { + double indicator_values[]; + if(CopyBuffer(ExtIndicatorHandle, SIGNAL_LINE, index, 1, indicator_values)<0) + { + //--- if the copying fails, report the error code + PrintFormat("Failed to copy data from the iStochastic indicator, error code %d", GetLastError()); + return(EMPTY_VALUE); + } + return(indicator_values[0]); + } +//+------------------------------------------------------------------+ diff --git a/BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.ex5 b/BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..63c7a4cc2d111281be41e1005d8d863e8a0ff92a GIT binary patch literal 1450086 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 z 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%0D1Pgsu;HNrVmaPWb_|KS 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%0Am(a|`T`BfCIoM5fKT>fJ5 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ÒB*il#i#Jy%U%Kbv(dfp(>u!^l4U01{6gmvya6kEfu+(6nxxoL~Cjteh zJ=zpdKZ}DSAzTuw9{*G${cwKYlYLJrGHRi*p^Wn+1=6js#(;;_e;vz!2uudXUsPJQ zMrZ>pNnncOQU zKXnZ}|F5#oMt9{osN~8=2&^cGK%3pujIJO%B2RQWY&DjDx#Kci5KRUN8e`9$$C5~< zbKZQI4%WUg+}Rn2C(Oaj)ZDVO6poxwYO!dWB_a&=u>a<2UIbZUh_5i2V}V|}CXQ|THpKuZGu zed;{G^sD~mSyO>2T~jmp95hh(4U&!-0PZfXyNzaY&M30`n_PuhW)gb}K0uL_;! zR~n|%nC~2uU838s-H5Ut9?3Isak6zjm4eY9PNPkcIllTGrtOsfE(jzd|2sNHM&In% zn0iam0-M;Tf$Mw>H*;y^zD|0)xrk zfoUKym#+e#x0|30(b+|SRFQ0hEi;{B-$Cd#f^o?r- zpuP{-pDbK)N?Iq*YCmH?ZYUz2)>;agPvsUknl}l7{geuwVh@xWf|^|7to0KOV74fP z$}ETmzfLSfSH25y={PvfXwcux!y-I=FjIy>SkBZ`970e_!^lH@l?-!U;daSJ(_jBj zm9pE2Q|>&Z3Rp^wDXsm>gY5cUKV`txG0W0a^{vvwDMTq$ELq!iY1~Bh8kea{8nxA| zUAnS-!wX@JI)lPU0~pF|k^Tt(%CLB0mxv=c{3#K$&J*IMUfiGIKi5E><|0=ll{j#X z?Ahlb?LiAO?N=Ax`psOh?)rNOp_dKx3DRyR61=8+p--6}aa6WPaAmi!Fe^olbZ@B) zoR-&NUkAl630Tm`GIrD2()lspD+1s0z9f9l$RrVc@3t(X7KD1sv#RRI$V}j`aoWMv zy?~?ck@&;MdlsEsX5yTkKc4W9^v=|Jc3w@fUPrk6b`+j{>0mGzzVR1Y(zzESYaG;a zR}|4+;us-`HLaLkZBOP2b?BykPm8Mt5F&1KvT>8d%iBzhtLCL03Y+Y^N}u9z z!@<5t#+!=^l+b?8~silVi6f*YGLLl-%0AErFbY|kl1>`zO& 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

` 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
  • ij)7W)%~;Fy6I;4Z?FlUizbYF|c9b=lPzk7E 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

    y$d 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 +J#T-sS&lN!;g=K31rHvaZ16P2&1Q_XgI)9$ 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�TSy9A-T&fIbQ8yf^0XR$4u8s6^`<6*Lr6wF!JFlmX5%BupHNv8uy^Jkk!l_&6HB5)s$*b0p{Di?ynf4r=~Jh}cGVHK~4w{?ie zAg9$nR8QrgeGJv8F>PtOt*K{YUCmPBe$6!=rY zOY1Cxg|=Cj#IvwHC?hAI(3DYM6X>5$^W3|Fq#zAn#0)JPl`2b;3Wfjy{G&UC0xvqf zHaP(4pZmylr=T5jD*T#77Oa5PFx{Zv376QcQg zPZ-_t>sr$FGgHV=B#NVVg`_aw&;ZjepB;5ty)7g`B2t$AA)Dd1n#7y<-1s0@KU{4B z_X12jHTXh^juW2@wX3k?7Av4Y#lfkV2#lnP7)GGngIh+?RFeMi>~G0zSsk2W7L|9Z zqmspP=4CpQJ@riT_G%cb4o+tILVsSK;9p^$*vg8agI{6G*w;{qJ#x1`!M_ID6<@sB z3iQg2bmIBJ1kcT?`F)P=HL4^QtEboshs>-7^NcP$-MAt~j0z6YzeXyOy}uo}d+%dz zpHIfXMi974LDtXT3JidkJDHM;*x(}|wrh+SGkMiji)|KD>L`|GXjRCDA4t_0+Tvez z?8vphQJ}zLHpPSu(XQT@wrZ;Z{sulubM6h7mOvp_oO=?L?UGw)4gLPwqg=Av= zEmyO<-+t@&jCB&H^olk%?nkFK9MZ{Qh);7Yc|@fkUO8g zFNbOI=%(F7?gb88q;*IelUi)5HtL=vpK06-AZQA_Mn=8yYlTZ`6?c-^q%TS|rZfIx zuwJ;Cr4un{Rg#{Hl33E}92N1#KW?%yJe3LBrXzCd>{h^h1e9r4ch=9vfZZQ!t- z%bMk@AP)uc^e)3vvh1jwmmr#-FP()$b|HKB0=I&Up%hFx^^+RVSVp?|na-S5Q0ZRNCN(ma? zMH_tSiu$>aACh=bh4bC{scen>NrRPlT;?_9IRK~AD^O+2Z1)< z_AMj5uN*nxEIJ7&9IFB%l8c2%nnxTA3SNPCg3-2nCiCdeAq=ZKdIFa1BBw~o0G$dg z8;D`}#=Oqzm}mA}T%dSeV66RC1kGw<#n#e$D0Ul>=!>4z6xC z;eyVmFuopxN`0kz9&Oj^&B4z}_I&uo`@HNzUT4}FJ@=CM5$Q-3HewUljDehCM!Cpb zEj!AO-2tWe${MfEimTE!q|bKUQI=EXEVr0kO9~7cyU+Iuz&`UBI<4Y~Q83{w@clum z@p@MMxZo<+|9o@c`;MvBBdOowD^4aB&8(7K`mGWJ-v=bnH{8O*L@yEWT)JD10cw5Z ztn|1^w)==bv7F02jZ|<){=Y9|Hr*?1m1%%=suLCgJ%u?pGwLTsW? zyIes|S{ng3CnU-D5|KrPoJTWX^KwrEIe$OhSyVJ-ZhHR}ljvZW3|_l?VSL3da!gavOEd9SUK7;iAu1D)d{hiE$JDkoIteD63eKj=?6 z*2L*3)|s7tc-6zf<&KCTm3fB%IY7q0U&hn6Viq33PCV|F*4=&NX79H+KU>LszSEp< zrWHwA%t;I=)f-3U!D4fba^xnI1YUk|$wQ8`%}hqFWCZQ$E$m4HmG?S;Z2?K^D$7f- zJhl&=@E)xg@53|1@tv8`}AA_lqir~t|yW$t7%0ZF=;3K3}( zQA)uTAYVx7ieQ2c_qY1~1O)!a_9gn0D=sYwbPz3i?Wq-RfDiRLHQusziciy!YBsG+^$opxI<|}<|&RxYYMW5 z)HROF)^Uzu<(z2&5{p+uJhjWg5&4))Pw^X0p^q+&^eFKQyfx3;6ep@cZ3*)BF7c%+ z%Q>CHR-g!O32;WD`w2INowmTR(=Ct&dI-5^aBN0<%$Qp0l{6C!5_TnAS;D; zGm6oxc3c5R2k4|Y43tpNhsgX^5Omg6cAEhJd2b1|I_fSs=bm%i@oY9yQKCU(H){;-5neK-=SO(+#Bm zL%k+hh}(yFFhoAAoqR}NbX<#s8l#coSYM~nB`HCj*l3k(M19{Jl?ur=|G~ak!6iY+ zM)LT>rI~Hlm<4s7Q0%Iyc{mwrqx7qam_(6xhHqlvtm2<-!d>dBk}gFZ1s#+qD}YlA zpZO%+QfKIB6z@ciKponIAy)o)AcLBam?H{Ts^mTeQ;gU(>B@HN;Pz!j`@a9+i#~OW zC~-^PO1&2B?}i}Tnd?n~9)13^j6MqB2OIvrV-8x#i+a(+`QymRU3;Y|p*WzktT3q% zL%W<0i3T0ZqW|e12Lde;!(hNCrJ?+_BY9fo^|4?2c zQ)W%Skv|&IF3E?0wo^(jE%Zl1e=ZEYJGZSAkTSxNi5D=KsIBvR(&)IVkR>O|*jn;E z42fl8Y5K4I`EUHum8lwETQ=a1{go8`3~Kc>n+Le{5}OKN=p8)UBr zjMOB^`1h7j6-`4}K$i*lC^V-$MlfQ92TR&Z8^vIwAJD}GMINX~9Dj=Q|5qqR?dJOJ z)*&nc;Q(D8G|#b}LWJsVYk?lLvb~H7#Z78+D9iATtIOligr3bC;Lm+DWOCX;PVZo? zIMK(L>EwOm4>7NlTj}?M$Z9HMr++);anhFXF|}qA6JwLA_BwW5H70C|lzN>_Fap#G zCvTE$W&661-9g6Bn8jUFg(_eiVYKWMM{G6XX}sPInlf2R{`AnWz+Rf-c?*vEl0Ff` zk^)~U?~MNX0c;+n!_0aNMp`MnY+hZe%_nK|Hk(p;<92;wbk?7>!ORBk?_X>OjyUgO zAp;p)2>uu~a8adS31h!rMfXv=P;2!MSmsa{!5e+RHD|)lf=>Tt%k6MC^8L4Ite>BA znN`d+=@YGbAOGeN;Ms8jpbc1h3SsoMw`WXZ3ZxKAwG**m5HA=b9(>!h76A|VW*GUdZHHHLH-?yxgx%Z14a-M%w1pSjWUD=6B1xt32@J~(vGE(gZMfc0cvWJnDPz-P3JgHi%WE@2rtP)ch?|R~wgHvV8G@FnnxHm%P1G zTbg1VbC5Mgj%kpy#*Jlb9!>!ijcwwa0zw`~O;x6e86SQ=Mr0}RNolU2+R(&)$Wt+Z zp+mynpS9!NHgt~Pb7q@9pE12%Iq)$xzPT=4f(wk)_wK@5h9Bvzet>?z9vGH1Tf-M- zw|RT(f~NmF!h>l>f%x>jL9Y}-ix?w)rOmh3Fm3qhr>4&T>g; z=r7u;#-xuRP?Qu7G^3X!DQuQh%tT+f^$d1*JBk{PI9u@FqeK-AFsuYC7NacKH1dUA zn=E>gO4qW2>3+IZ+vm^{J(AIlwySYOB;|1^is@+s^5KC{fFJWzm?RAt%_l0?1`=Op zwGk;mva?}svHZ+}*PgNAh)gS{OAJ6+i_HrG%rz`ArCPDqK6GBLaC4R1?lU3~OxA8o ztCR!fwEx&>Hb+*ysDu4R;LqaY4DFHcu?y!EoieUSKRS#p&@6`^n5}sEvIM^+GPP(0 z&DbI_sW6d1&n*=weXmZb^6wC`t5y4!`GT1nywd^T zfdA3N@xq3Ze5`zsW)R8=ST2f!?g&Uitw=TIbtSuG3vs&X}=INE_%>Y z&DVhXr!aN@WfD*oRr>+MJBQ1$W++&{6SdI`dhwySTS_OG`)$^_<2iA(PzeZ8+ zCw$FctlxL?M7}e@H!mAjyrFX|6#$Z+b{Q3eiGK zs)yLT%+gTuFz&YX}eZr*WIH3v>{jY%xS+hks*#mb)NM3j-@pm`musyh;4LZ4u>L!>fzedeeu|87X!2Q z=@UuEE4;#y8%m)Wyr0RW(Pba(;h9Su>a7d&6)QO7V%#58O0`(RK=LbCz^nmhX*@jm z(JvE+?Vy=UX08TM)6of;z^57tD}k%{q73jx9U1q|G@HQGU^~{}d&rR>7JfF!+a^R4PX*Q!|0afT^gU$2b-z|B5iTJF|!k ze}X2j5Q};Z284&e&yPO%d8BUne)5_|E0wR!PJ)!Wuzm?EfX~h#c{F$>3OeL$1X;uv zs1(fD;m`({hVzVtZteB%j8Fl2yHcAU-J+{P;=vCG!(1(t$HQ%I)qX>2%O|8J6vjsn zpf-W&$T5)1?>}q$2`5CAlkWv<#fOq_=Cn+NCN$KN=x}LO`$%{!fSzP`3ww3iADcFY zs*E0p(Z_%bk0{jWugQw{e=!02Y=o{)dMS=OT?SSlzLkCLM0~+e+VZO~4H#EeObLb% zz-iF@wTy@$#w<)Vmd#F0!ra%~aSw~kPE3fTr2rpbr+InBD?xgDt4>Y$@yviqv7+@&n368@DG{d7|D4g zjU0}qBk>dPd`;|NN5=u4TB3U-tc9gjjO3a>(R=ygDNl({%d(RM5lRYm;#ea9x1#=c- zPM&l!2etRsXwsXZURQ-EDupt9uvSg@%Z6whb)sQ>B)jCC?+3V3MWNoD+VSnCr~G6= z;eTK>y8F!?yiuVEOLh{6Q)^9-9;-3N$Iix~9YfWUR10l^6f4DOlosz%hiVuYPQje4 zukc53QJI@%Hk-=4CXBNiY~-h;_IvlUg)`EfiyPk#s;vt3nT*Q@Ulf!78YvU(dvEUi z3p5#dVTP@N6J#D1H}eiNwy#nCbBwl%ca|=!CmgM|3*uS_MtnI)I9}Hg+uB`PUr>sv z#TwY3-UoyvcMCrrG?buF7t74IF6Z3{hRG@|hF1ZnQsrh4u?N@zo2-4hxrX(3SXfFE zAvVgCwo4od9pbBDN+Ki?H$}|ETi9e~?K`_YJhPTD7;Z#4%^NNVf7G(yK;3==Jm1eq z&4N;Y;v->9YM&wmpp*{jj?}5og36ywtF1h&4Qi9J_`5;-SOv`!4NQ|)>P_-dmI=_k zJ=sReHrl`EzW)t@;&_7Mq|V`^cvu1hZ0f#mJ0-apc627V9xxqR;{Prm1HYQK;-hOUmoA{{!-t1pR(2T1MnLDE>sUED|LuDi{_0lf(A1+jdzrK2MRi*twVc zaZPD0D;aWK3)x-C*cJyS|*7Ua+eIh3E#z?XGcrRf#>T$nuD7w1)+T~(+CZk}N*#rAHfr4~dq zJJzR)+19E}6W3WMFA}2YV^YLl^_~OU^FKA^khDS5+%u#}pSlijVb@_%K+4ClvVVME zhtwkIBoHI0=8(B>Zqj9~m=GvARr4xBX<^E-(}~+gyS)@RdZeU6)fDA|4Lf9g6oP-# z=OR&AtFXokI;@k|@(2VqTP7x`w#zj$vJUuW#6=`B9kQ%;`RTFJwTR`-Ub#wOjc^COPG|s z?@hRMf`UsH3SsPL6Dy`+guFoFyK?B}%c$hiiHLtjBf6?2`Rej2sI6?Js~lc=CX-Dn z0oKp&pdnz9h6>cSz7R9`*QRlF1wyo;B2>boXaz;7x#UB2-h_;Pt7FJod($)uHt{2M z5vG?OqbB(b8Zq|f!yQ>Knj@8paz$^a6X)j)_0ch%AE6;Q0s(AWCv2%uGy0fmWppyfb41qLXn#ooX5 z=*=BknTANmkiXF#6e|}P?R!*I)KMPLFaJ8arO7cRs}6_$#BDY{_N|UHnqTK#5ineT zh%1eXYdYp?J&dE&T}2`g%@(hsNjav@dTOFEB~dn4(9*oe5H_XH#RRLIyh74BLw;MQ zjQ1zgSboX%$vZV^ayi;snJ=>J@KtNS*l7B*JKaiw{}1MJGwx(QHp|>k^g@qSquU1AHwo04ko%7mXGZ{*mz7s>~m% z8na!E(lzyBU4}YTM#&jY^e9JNZc%HKVjUgttY7Q4+8BZHVk7>Nqg*-QmB3ZWa>PCG3t^f;oCX2Pg-F{AHO`N>eBkD zxD9=3TUnv0yV7k6DiK3}_07j}{kO|QY z=KvqKvUAw-UKAE(cCi{O>+o;VFT&3nHna#rME0NS4w1WQ=|IEXrIBMXH*k<$Hl0>u zntVz(#B8y-n8L1ea2b@S$ouV1W#PD+Eph@=?i44}Fim2^fY=}&dvv6!9s}I2&iiiYlg~-;oK__;yM`ssHhdrfgD&6dx%pP8L#Vwy!?gu^jqM zspSr2yf3!o+kjrX45E%+yR?|OHH?_bCn10)cw9{U$W|MteN&~2Z6-lw!4wnx_OaQ0 zi9djiW}Y%zgiO8b=FmhdjC}nN|D}S`{8WA{7S#U{MJel|ca*#v>@jHCv>rY;R4_Mv zDK-m?W}V=E?=i`CvUkCJDqmKEMlZ|fwx5HG*_`DEr1VdjEhsLjZ!jq8Np=NpkL;@R zcBYDmDV|mZgP1}ZT9yncfV3(h%HMhP$mnBGRxLTLkya=-#Ex4_m89!CnhHiA?C!tP8$orUb_7JxYktMX9v?U3bJ>n*<5E z=&s!L&)=?<{{z@01iT1c&Gnc_HumKUoG0wYOgEL@zmTFAN>7@BDl>R-3SAFs9#HpZ z(XMMNqpI-gh?u&~F;cYuQ89kw3Ml2S!xOY%Y$*7gkxIQr+ukSYVOfs` z_v%+Rb=hnF)Vrffe&|h?>m3xT-;tNEj2~s_8#L>f;UFyM5y}s)At&B7&Epb5S6{h&$|IleUO}D&=-W!+)d`3sfu2ilg4p8&Uwbd1xpGeT@+P9!d|SEJsx@K#f$g@O9A=ZEN>9CF5tJ{nB2Q4ib8|?*^GdO3XMimmRQ7V8ezdyqq2QOvn zmZfGiA~Y|pm2f2mdA2I{SNibfvIK~K_4Z|T2-J4e)Va*^YBuRtoLoz~=3OLx_rig< ztN)&K^KLS=Wx`s`WG}fT0`Du|+BuD^k;;9_sZ2PB6e8O>CJB?Jsy72Jtk~TV zau^@(>Hk~N^P)ie`FBmXYwyqNeTFb@6%y9oEUsLpyD9T0+8HY$%lZ-qUksQB2ot$< z=S3fau)b)g4RAs|z#gAu=PIdj!0rL>zoLbY!flN-&}b4NS+F|b6QY}_WK!<#NL@H= zvWi~n5HC7vZ?;)^zo;$AF=hx`#$$J9{wilTJTQ_PvX+z!kIW$Zr!#MgD7PWcFyIUN z<3$)|_d1+Bz2Hj(*^D6PdTPn*uTmn8z-;LAp9H*DplNlI{YD>}TxrOJ+5v9h&#=$h z;nVo|Sf)n#(yGJh)B^2Co3=BDD1!47)T;}OThP5}r*Wi5sw#(-`UtI5*drFBucfuo z_hI2hx#;&0=D8@J-#-pOAUOtb`^xp&E zW0SYQ8`RJHQWGe*?NnaMC}@Hi>ogRq8bz_GL6{6@E;og%?%Dt?3#FpafnXp;rtnsR z$6`6no6_KB&76zG*iiAL!}RX_;XbHmZJkz5 z)ccgO)%Kk=*(y$1=T=PY$$?o%^oeyyX~!$(KxEh&z1F+IQ3z^seU3;QC9XQf!cux9 z#bx6&o8I?I^O9zv+PbdVp@mO?`W@0qt{6|b&^x0Q2b;9cFQb<|5Q30r?P(4ENGREx z=p^{kcr>zr(L-GA#><}|)`{(vSb!h&HqH?k_Y0uDDgS2KczdYuah|SpfS?feNGtsk zNts_e16aAxS8kuTT+7lFH00{eqxQAg@H3^1_~Ka`X#6Ki)e;mUms;};uPt$hWY_&+ zOOI`&@Y2q>WQ?iV*a|;$>+Ig{GtW{x11$Tf1#tx2siqMvcJhkp4 z;LRDDzi>6k`s}{18A!NAWJJ+u73Y^$pUY^_N7wYh_M#ib{e>-+Adpi^7;l3r)|kv% zgu*YGgz?p|Zay%-fEPGgn5?qz3`a>AIEAxy6*l%gZ(;gzwIRukKaCBsJh0fIz9=nV zt!~HPm8|ty?(3pPWG}~`j+MNARAjKk(u~-#FVCof`upBkR4UP}VIj)N9HR9}SSVvm zcAYyL1};u^+p=K)jH7iNV%RW^sE`BbFz(H?%%b0iJVEgsDbf3u*6N9Q@y* z0EW6aP8#1=$$@4InnG3Dj&bjA2?&3`BGhrs-nI{oJ@tHqO1n%R9NcR1tc0n4*w30@ z5!j=9V0&`nPvp}o$HJ~WP^p59RSOG9y-4Hg1%NsgWAbTNujC_rg(8^iiOsoJjdVK0&kj~3^SsHxxw_2+wF;I}RY2MEMIoOexk4YrZ(^K(G0=`YU z6r{FSuoTKqu$V!!~WS!x4OWWC9_3Tr~H(a<8t7aPh@ zgt70)VC`dum{_s_hqq^sK7_lIn*Jj_WV*hRn5~PzdQI&`A)7kp@n8fyYWE4yO9>aok<#e z+3A{n0?!m!*ucZB;t$Y~El%yrRWQqGeDO-IDeAT>3;6R-TS7Hjd%yF9rgMnBG_WFd z9yCq?smjTqNF9#C1_#Dc3ZuR_nVzo!9EH;|1-_BX$h!pniQ}l;c1x}BKg2sIO#WeN z(2mHMkjc-`{;c)<+M4#^HJHWU;T$$JMbfU!nLjA%3OOO>-<=oeN)>}kV9F=&Uk-iUj03pK zr4yf;DU8OkL|6VvYQ~;jdk)OSIc$iR2J(<}5wNUC|9#G0^ z@40)zeDdv1U#pnZ5%3lC_xZ*+@3q5s)`zFvKq`gst&qGoM$sT6P)h3%okOcHk{aFe zQKDyY7tlFTu-s&AFxy}1~${nQ-29deoAm3G7ZqUBUaVn^w z;k3oU%~9L~qB_Y*vB(ZIDNm7Zy}jF!k79@bV?geQQ$lGP$+neHTSM~yyVv%{P*Me$ zv95eu8s%MRag)#RlEP9#uV+_S7}9XuJh7qoK~E#2=}!6`ri2mnlzFtIfq{HU+bM2hO3CeFwPa`%L6ESYum$ii zf~P(h@WI*GD+)^+J9_?y=w;^_P?_*+Pj4q3=1JOJQ;$8;c*!<64+ZhEeT~`gQCn#B zvrn5HKnTle*rG`&PA>RxGu2lRc9<*u#f+EXPIO%hxq5lag9fB&ULXHBgj*=pc95)W zat4@1o6TlK~o*duu;Y59}WxTHznFD``hH(Z~uzEA@;cdy$-kTAJ$LJ0+ozbV**omb& zEPlk&Dej;6a##R$2Q3!bZmUbjJEOL8?+4ta2{N8*$r=$0V5dkQmLH$p`f{fill^O? zTv5lr^1#@^T^7~UoC-8qD~W(HG?rIvC2dj2^(9mHzG+GC%BS4QtckM*cTw`yspmY8 zB+ml$f=nqI^_Z4LrNox={7YC;8wwAxNjL@093t1>r7CuO1+ju%nQRMYVB4{!=fqx5_I9P{cp&hSC^Qf{;-T2iW_(Egb+GRw-{HlsG^% z#FEwOb4=_`evu*!=4L;yjb0(P==gr)kkDh9lBr>eb*Gg+rf8X6yDy^M zQrQfq>Ft==;i)YCWqn;+q2PYm!Bjw*sq+TsZYuY-h7Q+6KaTR>#=E8Btc|uTwBc%> zkPCg@WbiPBlqHH2Y!1n<{ZwK%kZ+!qeT>{@(=_|Qyl{&k@iUf)(mVf+%w(3p;IjG| z+EwS%OKBSyo!}CN$$?@Fh`u#vN_6N85uOoAFuR1jduHGdmAZ_X2oWH6_W%c0%iHp$ zq|IfYZzA+cQTT{{pHz9Yrh)s_Ty|si{+{K_3XY72P}G{G{$M{96{$RTLCLsF@(br} zfSUROrt)#TbKfy?D4Okoa8(;M65zoW!=4&w5JMJIaca9^jT08@%Z;EpyhssRQfpA6 z=&^!(2^1hbHlBSnx-kze2>1f61Sxwq%+g)m^qzU%#HzwJH_28I2FUgjthj|>e91K3 zTFBD$gAde>o5J%#S!k!$8~@DEqcpPvHSqO#36!fSkFbqFF=<2dEi@mhmc;zPVAyRp z-SY=eN4$m|z(txu8_7n$FhNGR$tLOKl1hDfg)F45icq_*F4*l9!%q%l68GPy)>_kO z?Ie+Ugg!aV$LD#7M109L`p-vt-ul#VLeah;CgnlJ5O%)QPrNym!3S?n%R<<&vu9x z`c&|2Z>GhO)BSF_AUavD9&Fh2x=>WJ)XN!>85I@=oLh&> zX%YKZvQVHx#HtoK(Kd`-I8~EAOKoZ)Lt+Ry?02YpC6o+eH>gIm4=;D+mkEa?G0HtZ zF`Pah$_7)IIWAJrZCbkAu0F;~r{ur?!?kC^*+DLR>;xWQaL7gf`>n2XW-DDlvH61= zo_X@l?AYaA)57Rx&3XV-6OBtSSkm&ENVHHp%bpHM2hth)obVE#q63y5j1ENx`G-h$UO~yXR?GXR4 zSs*0FwkG~Cw(S|t1moY!64`Q^vi5z4f&k1M>9!GJL?zM~Bo6Kr$m623~c`Z>fz2QG-q zFnu$hLA-zVgyeah=iS|YGWouGl=L#Qit5a{akDFZe)zRSxOhG4o*GoFqeKq{0?18VzDcnWMW;hEoBDhQo8$cu-AHp1H!O5ciEDCP{(}-GCqaT z1e_&+9CIP3<|NXy5aemSk;k@4;QK+K zN~0SIwpen(z^KMLoIbiAMcpHXKzZ=`EyhNg74bvl7oFV;Kzr9XDes9k*$&TE;W!`S zKW>T>bZp}t(t^*$=Eo8>X)Da$58c+7{&5!8O#(Sh?ra2g#*UM{e7-(+`-?-DrWzjR zJ=ICHoYjpYvD;HM5DPQgQr2N!e1l&h4*fm@SNiB!$B(i~p$AGSvN!{0&4|O9{j?xV z;v9|()JJA`&a{bZ=S8iY^D0LoTRBUk3h_^Bl_uOSsNRuz7wYsblJNa| zJWp{~)6|2avMUhAmDd$+i4K=pLp&gQQ{6^=bw}(`%nYPpmrcT&kCh|@v4SH)C{uR& zj5!7h)FggTRze^{(FkL}jmHR5G9GpK-h@;o{CH2SC&qvn#kz-6fSQJg zzD#is)6AO)6-U^;D~+ym2v;?uibe2B+t1v8wc3RH--Nd35R+|=PmTL zX`bz*Bq6}@SY8%newGV#$fYyfB|N|CsT_u$HUq6;$~e?~m#S0Q+QrK4l!Dx*$9yxD zIGTtz%5%@Ix+ndzoXy;`c**{>i9a0FwZ*#J3ywz@_}AzfJ%?8DBwh>j3vVzQ=i($G zUSGmSG@+8$T?X7o?MJq+E6`5ZF~)gzB@ZUS?dnJfD#rNmF4^qhUk)4`Lf2~eHk}EYs8Df>+awg2I^l2137n%7KIu)bEm6Tvf=uhC2C*Ew52-0T$xr> z|3geDT0egpCAzkSbkpxOd@6GrSuu!webj-$?#VoVzZ8AJO>%~ z3|1dxjihCHVsi)w1%%mk!jNc4nkKO$E@YOwhZ*Hb}S3XBlHrNT@qA*ZH^eWnG+q%qRMh z-I+|lB5Qm1g4qV4sXbtui1;Y)ua&H7J$X|t8g{&9Ob!P8oJ|(Q$M9&`mO8Qtl1d|6 z0~it(C3`BbKdaJ~XdHXI<`93MZ9td|zLLwe{6s>m*rHPv3_oJAj$AniN^3VokSZ#Q z5t%@6zCHowV5xiNZe)cNlQJ$wr@?z6xHzr6Issw^z^}UvIyaN>*a7fa?hBoJGlZ_DQ&`rRyK-!atgP@X9h%TYmyfw?0P~VHaxn=MZg4J6nYk#v4 z$mGsafaMl)Jda&K6d%L2_jja0LHfeCzgbZys4zqhoh(YQo&vV4`gc3uO)u75!PYfQ zyY_P8{~LMV34NaHr?g`U*HK<3b{L@fM$U`lj(v?$8!BNUkrs2*)vO;*^gfY}i-WL> zJ(FEQ=<~F0w7XxktcB2PBb`}W6231^{*~e;aM=|8&4D93&P9ZACskA<^xX&nM>}qn ztP;X*YYc^AYcuUqam0*UQ+G#oD@P1hxMMl*Q*l9F4nV>Xl;r5EqX4mD9A4SX0D6by z7IquZKaG0YEu6LurjO&%aZX**unOoj!-~nF!(4{u28L7{;%k_X)4XM}9Hn>wdn&i4 zhy>n9L6rTTxswpm9Ih^RS;>7yJ|d%cL+9{KP$O-4Uea;-*4YRZwuO?}~!+6oVPh ze)AC`$>XB8{5z>f&*N$)7Gghpr$%#*#JMi-ECKEu?=@?jZ`Oa^oepIU^_GB)ZY^tT#^a3_Xz9)-ukHM2xKpYw5xM_HNJy_@ zR{)+G#F2Sk=)h9ceW61g)00yj5*>WgT!YZ;%NJySqm`A`iiKZ}yc<5xj#|2{Kl?#X z=u=j~+~y94aXiIv@8TacjOAX3=PmNL*es4oWZ$5FLi91D08;S~YeT(KMhJ4BD0Zku zlg}kW0@++`*ZF_pd)@ve(vP#hfN|L3!vo7TMX!G0pp0N#3UL4ARhf>8+9`t;SoV+U z4HoLYP`r;{CNYBYZ!xT#Ckj&cllY-EfTGv5+8lJ+oh=sI&~=NFMRUcVbE)r0hA%OV zuzLcOW9H1ZJ!vN_oX0fGoc^pP8)X+Rt^AtA(3YYk<4(cq4?&)qw9_Avns(P2Ml3uGem2fa{HASqWgJ1;~?Dr9b=R6-Q;P9-8L66 zsAGpWgf#?O)|LJ_NO$|m{9EwQg?W0#tMb*;- zuB=#1)M+m+ir~6Vw~Neq$xyakzcC&&8l#l+!4rWrL3k8{tq~Yj@SdH}ZQtn`;VuhD-`~@@e6?i)^*S*$$3u zuSn}+p7ulwLWdY$TMFiX01l?#W4VPvb)}0xMhSp(zxLle;z}!mY=c0`7$ECcjFZ!0 z19;h$K~Xh_nahn=6Z-f<4VsW@dr*V&!Zz$JMMI!5>QHL?!E?ce?l(DJFA1vyh^%}b7#C!J=+LtGnh~^_|Lq^KO*4GK@zh!X za+}|w5&&{n0XoR(;x@}BuavkB^Y`8qA3Ls!87I~nBuP|F<&Q^U z*!?$sP$0JVw0rel_iL?RvBe^9mTH8W!u!`OHNYJ+{}oRRqlO%iG8(`+M6gJ31FLT%;swu?OaJnt3p}@ZsuHn(i+ScnNzW zFj$qwdVe5M0db22Apd}iTo6ha(UL86P>9ULKnp|i;z&n<8-zBoAupGm!tf2|6BnGt zR6QNaotp&7>`3kg?HDuz*2n;`OgZ1Lpj8qc>eU|kf$dl(-1%ftI={@4RugHrby~e1 zJ}ER{?9cydVQ<~?w&}uziv6uLuRn~opnTmVX3(X)jC^lR(y>Uc_jm#Y+zH6pbY;EP ztMTU6v~BLK82*glVD|xeIf`*8Ea|wAFpCy_F3Nyjnu4NE*WBSH;{2W@+ExsrQxa}e zcvN?eMNFAr26PaS1xl`6rYPB%~uyo}Bu?ufwP%NyvgV7FBhk#q`K?-Z_& zc(62dDKn8aq5gKDVDD!oqzgVv58xLx(>IQu?pR_ImH!&E;(_W<=Q=@hy@g@-B0+{*h*)5)s zAD9>VTUy%w>wAJ3!Op={oyGnfOR@e5XXuMV%jm?Up|r5_e+cb8xBNed#)ZsYSAB1P zrT$9>^dz!>7!{VRkQ-c>Um05c3nZn%w)`hbH<1T=_?F=q>BIQqe}-AMeH_}AjX z;h*hv)IqY%o3>RD?Yjd1>GR~(kW?@2f$f09MJV4tr^49>ti!6U8G*sVnJSzgmJdI! z{l)X;@vqcmBjAg1{t^jsi?@_c{8lK1RvlgvYIq!+kj-?LTRQxlG%}Vf?{^0~s-rxP z&ufdvwx_@g$X6&=Antf}m3;)5y2LiiSlWF}`%wq^PP89(rO!}woPH?X^+KcPAFY_~ zZXf(2{~MC{;}iwNWb~Eml~o2pMsxVJcDg3l^%$bW%BwG&X zqN6$1AD(OZ#0O$N@nl?@!1g_`ACWAOwXFJbo8C^;E_3kE$(qtU9}KA#5|%TlFjEd` zsag-ZMzqw*BR}XWK+%MO9Sjb|orkRd8EJyv=;7^OlANfC^Zu+v4w12+%j~48gjZQt zMBAIYn}fc-Mx*LNzQBo%P8s2kJFLq~o9Nz7>|3EE2sU%BrW)wxcP@}&b^t&vRmP}s z2dHU=Bf*Bi^>`U*Rc!m6Rsu9hn%9!81O?KfEg*cqe1jOC`hw48U?&fI)&>g6Z;U*KYHtP{X{VbKkVNu823yEQmy=>Fa5is*?y&Q$NuhxL`{6&uPeo7Qwo3 z^Pi@TX*~^uZjsLlUH@`o3G-Oa(C?yRcyaianPX;uWi7&F@-fNM7vd2#)Rnr-6Y#uNdPBVU z)bIzsHS~Qo3g5e{%gjFsgTd2#YV&nQC!D{Wm`$>9(Rd>iBD1*G-JaB0?c5!7ey`rb z(_}pJoUO;eUhB!_QE!(B*B2RHXi0S!bVLF~2a>5;YL5;X^v z6TRk5yEWRpf=7Q6CgZWGxaee3)sXeo55H|B*MCjOF3}0F)1sM>ZVi&l3{A+3=Q#!r zHjXr_h8d0WV=~zq4|A)k$s#PHS```&!t|tJVk)>E1nl*rRLuO=QC8Y@nTF@nYn;J6 z_F}j(QVfM3p4XGe=BeBpDu}6`$vXoxJ=pLAMPUy{g55`lJCooGLs~(DKxFMc21FW0 zxkn95a9U(rD0UVNj_2C|CtBv;_3K4xkv6$RNc2v2o$^mBP&wG&n~oVy`b28WTE))z z8i9)_FOV5?PkL{|U&$;;(Wwp8)K7Q1&g~nFcNSjs=R)?+p->$F^YCe&j2OQZz(2ol z29t+hH!EIDzJS1?wz`>)&C4;BDR5R43#GDf}@nFNg6~ zQByp%0593K|KK|i`lCC}(hoO|A1=b(y|B;bsHMztJc z00hBnO6a0kY&yt5>cKYQ4O}&n+CmC4bfC4{2gi?>*yi(Y8x@`yC$t4V+g`?j%?V9UBfcyk9)>IoEW-u1 z`Xl^4HNY_@SFlEyis44?P#>S{$2~8A548YPBbS@I7o_68L4w}2n$=pbXS1>uOs2xJ zU_Dyt|I=-$k9y^>ZS-MCr+cP5mKR}5j~)ipN;(m{XppVRnhY5A*tSNt%GwF}mm$*( zROk4yZPFipUnX&A9YKUGUNz(n;);+y5fK-C1fJK))OiQgUMsKxLPA_n&Pr$e9+Y9E zglm=wYRMw3KXassLXK_>qW!1UM3~g;B^msJ0 zW;ndVYnkULYhl5M_(h|?djXp;bW+&w*e+X70xxcR%IOGW|7p()r<48?zWSW}7BWrh z`^{mK@%AO4$VzZ^F>SvP4R{&sy%=XucW(S=H{Y7{xknrBiX(472rE3ZS^znGdvcA0 zFBE+DILaTyYji4xF=4S;Qc^Uuez4$(4)?F}a-w)hekpsCJxZ~uZp-bMFC#Y_I z>o`S%SGAN#kNm>%H`Hb>2y@p;uXeTk)*2{r=1xoq4Qc8)iL(3{ar>-*+0`}>LizXJ zdrVQJQH@!E#MZ415y5x7?f5Z&wnz&inDZx|Z{h&NQvf4C+`kogx5=HDX*mq-$2bQoh%G1YAH^ou6p{HZ$>o2=y(RRLt$g$nPAZhq7bwc+e zX7koCnXEdPCv)+Vwxr};i?+-ifds^r4)Hj$n%r1c%2CMTa0ris%h?1l^Vq}Wt42wEw8BeDO%;T8BGl;gM3g+MtsHmJIk3f4tp zL9IIvcfosBCw&rPl3lQ7IqwW1HLNS6Ae1)FVMox-or9s}{S^J@d-RcUy=dlbvY&lQ zr+BlS55O)_i?Wts3ij#lTJ6M8M^3iu&SLObJI1;!xS^;CI{eOpf=!sNVp(MtwH7hH z@|599XHx2g`MtyZX`OaOd)cr45rY?KNO=oL#Nm`MTQ>TN=ANT67~-QA_=UbxCCC1# zQe<=M3;86q(__LI;?#4$ds)SQi97qUC@dCrv_;!!XR?<`D}gvhm%3S35l#paZx7K+ zi|g-kaP7Ezm~1mtN|ypl9<@K8@7fV~d5H{uA_`?J89WH%Z z$pJs?8X#|=l2dH%fzH_FjRHJg?9U$XZ=M?G?08#?1m?~pUxq6M?|-0)fLwO!Ro&)A z1Ge1!y#M?k-?!6O^HWUaSM>6yu^NRUmjq^By1t(M! z3M`290)^TVoEZ6ip0|fR zDz~5XEVTrv41!lojKBUC2^*1g#sA7ZI~qL{tH#R9Uz9H2E-D;z%m`sJl6_E-OB$Fn zzs#wGbA?&uNTN4O5cAzndC8o&_^1+iHNm65ZLM&#O_bnjHkuZ1vu9crK{x-!X7Vlp z-KxnB!84}g@u`s zbx)gwRg(iMPkLWkpQS zXw4=H6{(`Kdb32izA~+#wY!bcd}#Th?hHFT^$Ri7#wBZ>$aWK~ z(pjF>{RjHgCBGteZ08Qq`?fdPdx6M^Rik+UAu6@zq((nwH?IyG)XxzT5HOC92<3<* zsqnhlK~%ZY0DOKs5CQPxh#Q!Dsz>>099SpuSKOl+8;MH7OpPsE&_o-@Nu5PeLI}qI zVyKl)i74rUL8EOu$p0v?0FO(OXuCoUhMEmvPJa0~si}WBWCMSOrFuf?U?tAKQP%ac zY|h_VFnX^g=MB0Dn@c3~~4?@&Mfdo%Siw|C%;lCrnvRlR@M zzwHF(p)G`PC@$CCQ;_xz`3j~>kE1A21pZGc0P_oIZSQNX>)!vCR%tQ#m%C->(#`H%L&Z?vlb|-1yU*WI)IuxpHiixLnF0hnoOl!r^Do%62sa zOVY%31d$u*_6ZL=*|9f3R&hY6^~brz)zS-1s2~@M1z!?06IyH&?O%MUrJ|%uI>GBC zl+M^@EKwC|>Q}N;JWU%m|C}Qe!^GBr5w@WOW@0|8uYeR1;D#&%W+vw#J7XszL;D26 zj}cZuPmM$+zqjm#&!U&lduXCdO} z{BLgoi}!=w2j&nlpfK>UCW9hcAXgkBvOq7{k>oEBN2i7cBJ6!*z4d?#UUD47H7YW0 z?kY<9f}x*YY#Gi}zY2+ztKWF){R>1eIBVsb_6@^(Oo1cE<=3KDL)`r^_;5SL;H!?u0VDfBVDFxd9wa z&_D0WJ){$=Yq7Id3A2()JL@$jb1zB?I3eNTFBt|wZ^@x~cL7bI`!kY4(6kB|v(pYC z1VXDQBRq%RI0AjT#QZTAaNI1$NHP@~0gQe&B<59KETf1l_2h^6d7y!T`I%Fq;;)!p znf7~+geH3j2r!V_wBOJU0Go(XuGJu|Oei@|lmfjx{}<(7BT$gA7|N=xc5?)QP+O35 zbC(nQc?uE3%V7gJMFr87NSfB}PJhaltFb0XzFTet>X0*#pjX~E_r(t^T2!GrcOroR z<|vm)T~kjflz=H;i>@N%2@gnAjvuF8xdG^udhJbIUKe^9c^DH%M4?AH6}~r@eRku< z+=AC6O98-mSV3yD3@TpX=VT}Lf{{h2UiYe(E7rm_JLPTFOn0rYi(f&gm}nrx*n{O=#{I~$xbC|End!}>(pM;IM$aNX%x zftq7tSWZ)h8v8`&y8-Bce#8|%U@nM}yv){KbYS%ey=z*a;2xjjro7((T}1Zbc=Rue zhXCM&#y*K}@pqdo?6YO*&8&{5Xq5vOtf1<3@*G0BiUKLnQrzp z$uI1}jcqR2x99l#6ww#jmSl z_lcN8O}(o~9!fdGVRk?Z_TlRVV$D5D)C$l zpR6E($RF)W3!u{IAlyG4b4DmE$;s4%y*_n^F?1+gcroEhanMjF;6VuSVXllYD08Un??pPR#L+ z-Lxs?W@vM-fYFmNnu)Ig62w`oXQ^~0#k;?i%U)3pMQp>2gc~Cmi6T&|RsiZ6Nl_C@ zNG=UBxFkjG$N$6^pz1$JvwCy7lMW@K_7)*@s;u`r>-5tD&0kM{wlUGV0bdWU`)eb` zqX1e80=N&H9zElt(;SnK&N2#LjEBdSmN7ot+&$#U=1habED$H_*ock4!TIgs7*n$C z`oYT)kHx_O94%0S-}DN}ch=JcBV{|@?G?qMGdIM|L|3b?A7Xh~O z3ZEoXHp+$YQ#%tNMnQ3ZAWD3JV(*tu6e<9OwhS4G=$ufBBm_U}Q$cly zR7UgQ7tbiub6F!0+fRx_BirJghlyCYbG$or^~hyz6Zj1*Ek93dpivONhPo?A z>S7J5cB2?pqV;5279g9H@|17Vj01W&2wA8!!)OINX;;F5wF&rcar9N>Hp|hdj|=U; zeK0lq%!PXl5HH&=Byfp*=qns}$gGY5V(6*8*VT1rZu|<_h>BXgAO#WLYwGk#-B@E{ z`dcJmk+Nj7CM~6L>tYH~Z`8GtS8t?5`K$oB@>=2HF+P%cfb)6ao}sV`5ZP??&D9zY z1r^iMvjB&aiam)@6ri8`(lvZ|xPgcTp{at5i=@`UZGZtFYN`kRehjWempFQs58tQ% zh}Q`lA^O|<){lbbq^3Ov&6?F+Y!Y9b*K#y5xUKb$H=9%^J&`qp;RG>~Kol@e&ONsD_gF|nI^V(D3cbe6~?5GlM~2 zIKAI#EWsm2ag3{D^I4vVQ+(Vo1a^Hr<>`Jg;&bHV!zq-YXWX&zTW5sJa0t7R|HD9$ za`KA@(ShG7MO+i!h|G5VSN@NJ9($oRism+u& z6pOWnB79rQIyZDzI9!{US+$D)ucl2?*sTG#CN!cvHmDv=W!%hx($y`z!e}@$HcS@4 zI&yfdx`h9%PjH18DLlyI$Q2h^)s5VkH}*^awSbyb zy>d`92*E*_YJ@$jx*?yPY6^{6UyCN=jR6tz+9r`mjN9p_`vZpqu?~S0)!9|VVueqX z%Ww+zp4{Ec1-y}y>e|Sh-0V5EKv_Y{1#T?525VR%<-cW6S;cg2DDt$FU*;~vve&BA zD9^!o_zRzELgqHSi`7rKGMVO5l=VsiW$OjkApx2>FpAJS6E?Lw%`1{d>E%@VAEwUu z&7-b56p>`La2^$uB=$X9OpJ>dS7%Uh9+n@?sA1VFa=+4aW*xR=b{{feOfiw%D!E&A ziDJxz=ZkxyGUkRwovZ*Wyd}}yI2&W>ey2a!YyYHk@`mhH8Ao*OFJ_<-tUCd?=Zj|R zR}ZiRoOwF+v&OvcK4)#Mm%DC|um8dPc-uLc$0KyWDrK_$ZY_WkcTR)bpt(#x zWCyOk{jqK>pLh`np>9j4venLkIY z`tc+vy3NMoq1Glg&t>S{sp_Yo$@4E*unA%Ba*(n3 z%3G(V1UW!g;N)T?c@E4N-;#gI@-VBlAV1+mc%`%}<3@1?!WP40bu<{2yzco~}c&k0=l@RhHQ{FmDGC!iY~i@&wS5a4CRPcsJok+s{E0E z+|ZTd6dot0k95zg5h2@Y^n@r^p!AZO))=D;sh1K8v)f|nCC@uw1gjzK zr&p4iLAg-g78oJNRf$rPHAgYm8|xu~+MoM;3)M#V{-?UgWZ6HiH5KlS*Ga<+y`H44 zD}U15^vSNt0gHSLHcrjY zNwI#29-U9;k6ubd4DP`lvcz;tXT^a$`>EI_5$sbEWvNy1E$3|Wau-QVM4pn2)B~~J z?PF?V;Ka>J#^G`3BYP;#1%jH?L{>sTMh7h-8_?R*joRv4{ck5Dl12fom0RoKMP+_O z5IxjjUsa~gN{tt^;ok`G-Lu@~x$zc`=94#R5vX-yx;pp!AKVZ7{wnTRo1%>r4X232 zzDcAC%#Zm|m9JLKOx=n@+l2fbfsKo~y!9iQ=#mx&Oq-{LYlWI#xF0O}Eb*WScugQe zR>P>SUw$e~{%dsY)T1-9J)~E#oh86mz#cAzKNsJ?f8T-!7Oo@I6XghpWPTEpKFu$$ zEC~ry=Gz6`4vx!(5ZV0VqzkO}WKlyuF%~MHM8C8k!Lc2(*rhW-X8@wwLl%Gl`Jqx4 zHOM<`HAidW5|$S1>8O)?h~x%n%cJ?0Y22yqCY{iiwhynk<_y?tMiD$jle8K^LNhy9 zt|0~j9IGwFe--K=Mf`LjsZ72>(*KWo#^t$9q?8@%o z6F*>c`xV1YmUL7Qd`yTmFRmSSiN=1^5~CicZl>?H6SkHQGz$1}@MSU!)wN*50X6r` z)PFDpV6vp?)+ea1I$C~(Wp{$#F04>RvMCyKFe-l}xlf4PEVHU5;u(-G9Hm6+|7hTd zZs_gr%@uG|=EBbF8T&%xG~6z~T;g{I!}=V>0skTaDm?07sq11ru^I@Hbf8u2MSkG!>8eo1 zMxtXR058V*^fu3T8rza)mxFB+19Msw^3JVUejp)-1o#_xc@ok2Jj$rlOGV&-&fZP| zA~W+Vi9UE&V%p?ynZcC& zgecc9-0R|M+usk#`A#r>D>_5lb0P7qMEu4|y6+rDj0^*m!}gUS@SwMzb6NiQ8rQd> z=QU9N;0G(c8)Bc;;~2FC*uTNtof0rblCRF^*fQ;O-$vD-2Di z++5g`4DAk^2lS48qdL&F^?{uLj)Wb1qE#49BF&E1Z06_%xyz=>#St1L`91q%Qi?tg zDypX=8e#QZ2h5a(UTN`~hwX==$n6+fZu0o6-l{&h1cZHXPo@#sOq0bm?Pyyyn8t?i zhuuQ2XUpvPn$Z_m;`L)PuY}c585B%`F&!o=hAx=O8xS!lUb^3T&LC#8L`U-h64vLW zZw@ap7H$F|@^iW{{Hqu4d}_VApOPs8_TPMydmvFSCItc0{og!e*I0llK$w~w8F@7j z*(<9ZouDBUufDUiR=rOGl}FxdXf{+QVO4C0TqnYZ-UY-KFG9>Ex?-6=!@t*q#yCMk zzTWn$<6@%E6Rl7bEFjXR+mE2RT&KiglKK%%b| zY~m$AWELF7@lHtJgvACyyw^CkoN9W!8i*@{Vf$MJ9?cb4KMGw)EXOR#)<(I(&Kzf= z7q(#8Ol-n)1~~vS-~XGWSIFd1D>p-%(XWK$b*41Xa!LZ-^f()lx{L{LbtcTNpbLK+ z^xeVe?VHk=9?IJQE$a2nHwP5{4N*FiaO#jPgon}icFd2*wM7ODo2s{9D&I59)KZYE z`JgMQi1rz^53Nmi>k*=lU3&Gvhxv-M9xts%hI)eS@md~-vhO*-~igHpEGyfp`=@scGlaBhnYx?rgR?%(V5kq{%`K}p=HCBc_DHYS!tdp3@eaGME z|9}E*y5k;fp@pYeQt(-PCy(_RVYK;VKs({|+BGG(T_lqs2h8QeBYPqcohi^Ft0yUL z@_dO8T?kd4t?7zEkQsHz)&^r1;b`M!Sc;V8|6R5)Ic&Y#GBS}&JUT^W1mJd`heoc& z#M5Pv=!)q;A*W5vPEP4CZaj)?vd)WxsF|0^w*layAsj|?s=n^Be6`_u`EpVn3W= zW~o^$VG_GvUVI8~cRU(bGt6JV=eDuDuT7mz7+gdnqc47d{ZQk?G0ob(=g0CH=)5^6 z=AdEu78Z{k%6`TKQPCUSPpYIPpk)jfAqhukjK6*$r9AQ@k!KH!#F#YDqUaFI z)j=C~VH4Gq>UaSC77zC-Pq8h*&8G2dUhjtuTY=wL!24&^M%h)(GN`O+0de{%543z% zd5SebLTs)~C_Np78a35^T<$O$Z%n!P1h`Briiv1=&O zfI1a#G$p=qN~;$_EPjrek!=g=f;@y6k>< z_3y?}!d}q+**6lr+sh9sif5|Phj|}qTT>PqY$B6hu1({JVExS(0$I1UbD}l{x9xJ4 zx+@_?)xmcr!Jt{K^s-(fjWC1UOG}FqmQkJ1iEo;GYcD~#r%#k zN#+F*RCrPTNA}d&Qao>WP%!u9x)KI^uJF~d4gCazhylX7<}0QKj7@Wxy3?q*`F{G$ zoXVIvJF{?)g?y*Kg=Ah%hbxN`HM<01rOpGH6_1HZf-|J+ApSiF?FZBa&tp+;?@-hC zr2Xy&&1q_Dqs~2(43nU2l7giC`1-}D2WiiPuOQ?E;WNv!uVOj?X7@-Xd4SWreOdVu z4b4qq0KgSE7>-Cr(((yy>q>FM)gq*~ae;x(*h8*WFsNEU1glV7T(6 zd91epQ=cYND}Whxx#o%dIJ=4;J>j7q#Kv^fCucLl(h1z^FQ0V?31|1+5pn49LrY)A z?h&zWTzVYWM#r^x6(hXV0zNw+D*;nTXXU(V=D5HBB;LG}=F908Qu5=aZkeb;DYybJU^h~7n zjAs!NH=|f}WM{+t`s>zH<{V%%de27~`=rW|~YnsEy$>BUp3Ft0KUMM&jdi426p)~Fppm7yds z`)MVP>FBrPORU#oGHGxuywGHxlNmfaP2%*hF9s~zs*Ik?HyI|J*CP%7MI{uZC55fA z%G#ScikTRzggMfne+~xe7rJVYz|<0%38)>nJQ_P%X6RjxZ-x0L)+)KC=ya#H7frplP$8bCd=FN(Lz%C`zLk?j~^o=#%< zle2@>;|IjLJnItSya8<-AmQp_QuG{Kj@s9nP0<{%8bXCAS9>QrKA z<^AvKGZj!9fjOIh2Qk~tL{t~{hFpn?a{Kj^|WW_&I-0odv9 zs2g;+1tEcbDejM>0K_#iKgvrSeRJx<^AqW$k-KwH|K6wOxgeAF7veF?!+3d!OV)^&F>7tc{X^uZF@3zH%FkqeSMqo4) zSB(-gE)oevf~My3CtPoK-Y{Ci&pPy|v3$!MFP}EB%Ia>1Q6lL2S=X9K?soXK7!6|$ z%8A%r&k`~H`ycPvBOFItp+jA5+Xr+)j-<2t2OmI%GV?% zB>?7mYTL*+6aC z;(C`+S#?%#;UJ7(sw_hZpBW$jxzZC^QL|U=22UNGF9mL58#jHdc=nAj+e4_ntr1|G zn;eoyf3uz(AW*h>NKzJ;@V-=3XEY$8FJEfP&HVu?lkaW~{w~T&)^YgXYY1_hdGh7i zX8_!~kzQLLC@QBPMr?u8f%#dX}A+2gk!o=Lg4u`?R#1S*e8K>STW@K$FW z5JkwF_r07sq{vC)tj!C4(35?Ob0|#sjs`nY zxhpd4SM_=d(?(I3Kc@1MuCwGFc9I%$_?mLE+(HvqJwnvkX*9|vA1MJI?z?vso5_Lwal0TX4Y`#h zlNir_vEqB70cm^Eov1_$Il~4qm55feYOu^3o!T?Cy;2g|tC8~BidG!Dtok`MlPRQ- z4JP+cshZC^HPt7D*j7w%O&O5m8aC#JK_t138-;T41vQK?gvrEh%5A%btr8PZpv$Y2dH$t1GSicL&db(A*hU_O12RUO0kH9Q(-8X@eZFSOu<#~tdZaxaf z5RXP^kF?Wx2}fPBRC983rj+8nMlbQsOoj_Rkb(9R=&Pw{Dp83_LpF47rTy&$^P#IK zzpHw29q2elIt4sz;y$187+)jEK!&Z72{{paM5i*pb^Dz_4vM<~Yp6;33_1T4%+724 zgoO!p9qc7)`&zW4$dQOgWlXnEiLc88tdbbZk&a1o zfA$l`Ew0!XQU6cp!P4?0-$jpJ=#Wpj&=_NOC@7>a+8mKqQyHD6AmJ+@5#HQ{f{0EA z)&a)W+?FsAoGJX_>R>f9_jWeL+WLNLjN&qx>sv*`UuS_ZBxKKedNWw5ypN=`^;9n) z)3RLm0e#?#>l|tY2FE8S*D-KekD#Xcq0M`%Yd{Wmr62{m_Z+p!m`33g0Eo3ctK8Q& zwVdF#2pI|MgpHNCASF#rw!x-0eAv#s^w{9^rbqM_qt<>Fn9VX&Q@tUp%LPPw_!<7g z1zL`DXA!W3rejV~i?gSK)o)#ah>;$+CwwqTyBiQI}tQkI3 z`j0R6$m!`#AVJWiVn|gE^{XX+E86hp{*<)Sr(vr@!Mkc>C);NEyii)l5iEm}FUcO1 zS8f|AMbgI7h2<(3(#OK6coAwbr*FL2>rTH1Y~7kK6vNyjrLUS2bb=5ToSGiRS+i&( z93Hifj?;lXu&ufNfHoIzHvpqd&Cf;EmwgsJe~0TGj4N zudlJKmr$vS6gX*$BzLF7K?KILR_2iKs%$$n+ApHZr`d1NPZKeNhfjggRPbC2!0jHQ zX7gUnU0M1_3KiMv=H)H6?i0r)G8HhFkakfdrwIN{$b8(8CXuYq3=4ViPqG5XyT`UJga#X+)e-_sB`mD*`16? zDPRQ|(OL|v*gvZ&C6g`2n`O0@u!rxa#1kopJP&;vSC|5+06J_*wr zns3$aM&-lDDjYp1*+{%GJ|ftsz0uu$Tu%rP5P1o&1&jTYE-2N}KPQezvx6MMhOkK| z9!5hsCR+m~lq!yDCEq&TEh}qazxChN4H0DLyan4z%$lejjJuj`2 z{+eyV_MCJxCH#k8$$m7LWXQRZT)+nPvd!7A|4O?M$~S`&Aku)|?{ponTnNaF!YbQ4duWMmxsvg_1OCg&SF>9T;tyJ5X<*Oi zXrZ{NMbP0VtYnvorGN$_6+Zapg5MIF_tBmFZfXMT;2XXgKMP7VYNvp?<9YTliLWVr zD*cv(+jbKf3ZBQ<6vlfb9Iiy_ke|Y3vRYh_(1)@%dGl;hwXHo)^feei){)3)JwzaK~!u@1t0{e_YD&0Xyu?E5p+WuWFu*d#z=yS9f7tv8&S`@tMCBgv`{d;BxvsidELc=zE^@rZ^rIqv zHmV8fBFvsX)3Wp9u>vcsIE5JDuar0rF*>HLwUOyf51ggk$cenUo!4C-?t=^q`875b zn=rm3yU=-%ae?*S%nt+V7$oDy zT_UB&7)gWCo}NsX#^1n$I(t284pSo4eMVM0X~T|BeUaKrP?299V4FpD&WoW;Uxi>J z+-wvVDk2zAJad6v<>qKNqgXAFxiVufqW@a@-gZ|mP6IMv{(tde>sH}V+@`#-u+D9O zr?(vw%Uyj)g9?h=mx7GWpOQN}xceabnabSYV^G5Z%3m%zed7E&vb^Z{)VmG!AIUoTh$X6YGE2N z7S@(S^9@>#iw^<0rp+XNwA(S_Vfq)S?^p8u5O?H&v&6e{wV{#pd^GWOV87kOaDeUqB}gLqT`J?U=+5(P5IOb zXhtVxblXHT8BtRFZfmbAFXERDdNm#P%@9aQB6+?NsC|myD0WpCKtiyz^Fg^8+H1D8 z`XuX#YTkRVWWmSVNg+?z;hIKwb(ByGxO$Azhx#IA$Sc{2vTap=%NcK_lp$J7igW8?U%sm>kZNl_`>W5Pp(MO>t zp@G&dA}|Oqe=-jX@zvA8`T1;0LHP5Lj}I1t!y3CrnU5`5vxr&S*wqR21&8zJ!_6d4 zA@XRVcCq(5+O$|3{5r4U@S=l>%uf*=^)Y9$--#kHeopZ%zae`^;TXUF)-NW|u|A?g zchmF(*B!8=ema2RiLv9v{V!q4^BjV%f~{h zvc5e#{{~`w=D;xnQH)mcw|6Q9*WkpRWiT;7PA@?QqXP{13M2*qmqT~1Ek zfRI*))yGz<{v(sIYKxvj#o+8DtUM?=iVBSjEq0)l&S&u0UkjK}9A@wk0HboQGq2I7 za+t83#s{k&H};S*jA>n1tf0!1vugrc(rqHBi<4$gpPIK8Ml>Y(zjPZaUXl=x;#~16YZk)&U092TbJM^I#U&g!_1ji_d)tC^Pt* z^N~lUiuv#hv4{(v(EQ=vy{H0wYZK~V=la$0!&P@wF*z=}A4sD?q|z=g!Fjg8Sm&XM z8B)+&oP;r#lptT9Hc0Vyg|^3YQalyJBVtO%#BtO?bk-;|`}z~8x8RLc#1x{1_*U!J zj;W-ip6O%iVC02;WXFf-VljdZ&g!sDUQu+6!`m3T44adW+P|z`nrP-P$T!XDRh1e3 z0A+@kKS4V?nR}A1shA!{DlP9NynsSQTiCe`3&Yv9FAy5}PzfF#4C%Tn0{QP0DTFzQ z?vcnDm$psNfx!8tSd}vC?$jY5`_{C@R&cXn92|ov;V>4#VZwF=-zGB<_&a7IVR2Mz zb58U^OwCL2HnLy;b7566JpSO>)m_7FkhKIwiJb-TF*%y>jywVElAp z%mgHYnl;0wJjC!%L&^GK49|M8qma(Dk+*Fm`@1XLHsB<&(LW<>A6Vc8ZyR}kl5yUv z)t!|`Kf-Y^vn^=VynxzNGbGFtb@EQbciwAk^Fr7~Iwc<`!Fu;Q;-_aPI7L!eD^beJ z+clnOZP1g+Neb|E;#XS$Rwv9+peBwz$ZMj9hVb=Dy={52z_y{z|Ia3ywjxrIHT&Tu zDiTQaS0bkF`?m;#$Mv;?3bAr+V|^P}RQ3$N^+c!W6FOaL7*xI^H_c@7i=6!^oYjeW z`;&S*dBn~8(l|TlAuP8Q+jV;-nc&bnNnJKD-yXh;Q0HOVu~q=-8eirS@1Mbl9DtF< zlpVx)D6P`)oY!_r?PwJ*7zp50*7WuMsWrtDF`FYokqN-t%_sr%)#A;;=}H!egWZ1$ zgP@o#pT^)xMvafUkg^xLrRmqtHE0bk>>Xpwq_wnlGvz-bsU2`gd@997@c0msCf>R9 z?f@~-Hqx9b-Dv`Dji~{2b_W1YZO15ed`;c9hM1@9Fh~!@uk6TAYsWdooXz!kUg}(^ zGkxyN*@BfL6#YUV99Vu3n$Y1sXRjOLv>FivrMz9nG>u0n)#^@0C- z!^!~4j@2^#Fqd{?M>OW8ZpvaJd#Eb#?tJy2!ql7!a3g)QQJ{nU6AC+KW@Fvfhfe=^ z4S_LcX8eLusqR)m-^*s6-9O`-=|;EuD$|fq`GmrLwhTQRJdBu z-zse;`7{z^)q{T2gxMHDkxtO2zH40XBRu{kcZm6^ z_ycQ{QfC+IRKoGV4F8U#ai8t(M&HHVDJxnZCZa7e{{k5dfSFFQDO1q4ONV-g;8>;3Pnal=+GN6?%wq~*nJxW`&zS`~_XFIyW>%3QW~-*eeOauMS+-8o6^I6t zGD#5|u5KHOf%K4f;KD_wfuF->4$C~D{&Jg`IsRTqc(kFAS--fv!#hO@y;P}u$8&c3 zBSUC`AWyg07IwWRm;VERc87#5wgR7?VWxB2i_r!D+SkVyPF{ULDjxD4}zy1eaAh^)n=PP!AM z(su~^ptq~yl4@0oM$))vGqrkU>O-QGeR>*aFCX$7p*yys1X{yMl*fewrG3eHPt4io z-ZBC{*E)FP-=i<=LsoR2B2ZWeoJF}%;*x2Lsb?24fbmN}e+ReTnFk?gx`rMDS^it= zdnu*k#3JQ=r*Wr6tytz+Q$;GPWQRE$=FY|K0m55UZaXv}3Tm(gki$4Kj#Ac`(eq?( zszHu*)lL!7cZAgT+*dN*zR6@%{^|tYSAQ?A>Bl|9+%^)f)=Ne~F0ILbKxO^4M3(8% zCR&%S{uzX?OVHs9SF`C1O!BO4*j{JbpzN zUN#wb1wHZf$nkO}BEJ-m?1W2eF6moH3OKLRb}~2Lc`Mx)slv+Cjb-{K)l9S_C2tHb zWafblNZX~M6Fpn}_S#E3iS4;h{%BuOCr_%1+`#bT@YrgXm79)WUg@!BjY6N?gN;Ys zSUS!DrKnV~@RIc>V+BSg1=NBiq5@J+^z?%8K&{<&Q=N52-;M4X zsgAqE6OXaPg)8ADDX+d=5RcLL&Q{T9QQF%RiYOuxE(8Tii5qR#Ne`9Up;QUzsiBp%ZZ>Z z&5K{bE`OTRujr&O`}xHaOH0WKu>VGh7sLPl1|0sv((A(${a>P;swO0J@>a`rZgYJc zApE&q<|S+g&WR0dQYsPK*|>c@Bn{}xZLC3QZ2xRC+LI^w80E*W)Rgt3Zg^|yn@%(n zDA|nSo3^I7)F+lPLS@wj#oxXm$fRkEr68QlSY}|zniETq3KEh&;$1PBua57&zh4f@ zeA4m}#wj$UN-uBiyk;AGz?cgEIdMla*v6~DfInKFa!6QK zE`Ejn?#Fpwid%hl=coeyL*pJ1QNkqdaj8$jxFcR*J^x!MKg)JmzyfK!8N}P9jUjNE z3Aj_UhsT9#ngBwe@h1XT4YLt-o#ifZ*aJA<>1$raan~%|umQC&D@m=+0|jzxQKu7m zlSvj$3(UiifOb-!Un9_J&I0W8KoBnkpl}1f*d$$)jYRElw)f|ea$HqvzC-ggKQo_$ zg{UNZuiLemyWTZylYw{Z`bG@$=IKthxy4fer@*lBp_0p5KAUiPE8ml1x$s5)G~e

    }Xae3#dAqCalESSFBQlpvdEV)$A(Q~h(SqcyrrUS5&7k^^P+CP;T1Nd7G3xO)DN3^BFiNJ3@`Ef39oF=D7OX>9uO z3426-S&P-#{F#w#EFf{yq&~S+-d}L_A@{ULf$H$Cz5+a(@hkL;8Lib5ZDrY#&yet= zfl4Z2R_p(vrH78R0i@kdu58cI{Z1>uE99+zWN6e~!HPk2%^8!tp)4}?HX8=a%TGM> z9Yonf?t+JPtFN(7p~2J$b|mYzKAh8Z#ARYsggu_h3A8H=IHN=W(+3|@H8>eSw86Rs zcb-q z70LxMg%Ux0kSzM;hF83=XwWdy)FtK$m4N0E*!XV9T?2opZ7#;J`!7Qk0q=EYT4NXo z91Qn&=b5w8wv!_1s4f1KvPi+zXH?|a8DAN)DS{GFikxm?@2bo0G2j-8(pO-kjs$00 zYve-7H2kpr7ZV#-i{EdfEn$S%I+s-7ps%%QL>dA&sy3P3U=PD`Y;;RvqF_pUFLF@P z);<{)j_*A?C=Z;Y%8Fyh=-O;x3Gf@11Ucea0)MNt(MC9y&N&5 zbW?s6@!eX`_B87ELuTbRjAI`5B5c*4XN=X4o`Z)9CUx2l)pj-`jTx$uIcHuy+`1rR zi-I=^uU9O*L}NDF6}Y5xKbs`$lLx2hn|~+es|5Is$+cbc+SVW@pkA~?ITdv_OPIQU zG5x;?-V&++WSd{CEXR8W(iLaj^=HQ>nD|9ZAjh25X{_C}dpj;K&Ng(PQR?fgnVCb% zd^DA-`g*ihi+j5Js<qu{uCDjelD)YpQ!_ z=C|+Etd{WM5A{xg^nUzYGwNGxC&X(oYa!-+wcVvP(5e1Z6r=d%QUMtp{#k!GA>A5T zj^=Jsps0wFiY@>5egt)75@{dz1dsveQ5x=qWxe0qj2zoDB@w?^u(~M+LahX~0V2?U8CtQ?(6tC0Nm252h(?=o|G45SP>9Bd2hk zhEoDs?q04$M*;z3IwgyTQgA^}HpiNk z@Ocq=<*jRm>};SLn{i3b!etqP_vu>knLZ4k;a-(=$@08J``1SXUWO(@>RpkH4YlmW zTAPt%H&0VM&7bfG0pz=w?B&$^k1LXkU)Kd4K*0|#xPS6Y7ePEuKtU4_yA(L42l>Ou^_mj7M8{YeAe{X2i26PZY4| z6|SmQ%{#@t@OZU;wDbePt1zIpP__%r?cbr>tkwIWd*o&q`fnKx*zrt8fcK?wPa5`q z|Cw~+>2v-?o#GL69G>6z+z;AELwj!bOM#8HAMOR%3IG|OCXv$ zuSNvjoUK?4tON{yGJr|q4<7T6+V8~%@5v)NI+)O5%92mQvn02)b{KxRp8>Qk>Jc+@ zz(o3Z6~KBJ`}6;cSWoM)4THbw-Eu}Zz{7^kFjc47p&=vtsRKR#eu6?qe?_1n9bFKz z^?blbUXCXsnpbA}0h^cQU8!{}7*V}0bCbaD$02~<(if{QwgbLlilQ&Y89W@g`Wh?^ z>W^H6&Y4NvDyz#<_wx^B`!gXr;;|cA-iEKmdif>Nb-OXo5{Xq5&opuS2dOad$#!kF zvwQ&0002>ZiHzfNYj0UXDnTyr9yT!f=BUFZ(%HNwTAGsMv>&JUo`)5ETQ;|SzPZ>Q z>O9Fk-;IpKmM~S7n)3!Wy6)9=F?ITWE&RJmDnT@;UV%T#!xWVlD; z%X$bgv>|)SPWtK^Y@Xrl4nES9x}8S8Cd_g&3*wR~=8HUhdpXRC>V-*jaS}FQRtz&* zU{r!r5mCOA92g=DZ|Gu&_f|NC2I@BUz7S-cn?VpODxcSJt-OM>wtUwZ*ojH-#(&qc z4Dm0y%_mVt-2xZ>3|xjnqQB+mmJJAFRd8<=$Se%TfBReMT!PfVpmFcu`hw$#?}k|} z%(WquD9K0z|5FW%i^&GVB$)OK~RuTQX4q5$AhZyzkt{fj^YF^Ig}VtCU~D$zoqV z?0LYkvJloCfCYo`&be0f4e)=msms52kgk&tVEJh}VF+}K)ERCJRSH*5){Gvc_?4oj zT&CJSmc=wZW)06FvU>$@%fo>x6X#Z@B) zIbRQH3Q6L0=GJif{tqfjP{jLoh4)VkRrhbLE=w=l+9*P@SznN!ay`6pZAf_%d!WWa zE_hY*zp@uaqq!GBU7{#D8je*Saa#U4t=8Awt*|uASBT-*HHm2bpWdPEW(^>}@5PBK zdT13y(7tz7*y)agG_68*)e9VwDE2BhTxr)kyj&ozCYcEXvr@Mp%Ml^nrB>;$7GL2c znCHcq5? zu_pZZu2b70jFC0fneGUsU|sJ}FZF6gs7oh{m9Nk4Oiv=!oNRe7N&wWcp1^9Wxqj$8 zl)~l_z4q5LZPPzbjH&0#V%d&RLk3hvu+LwPc07($RP>3%Pg$mg%;(AV1{n@t%jav_ z!d8H4s!r;eujr8H&jAw>wV?x!f~f zk4O$5wFW@7yQ-ZLu@$CM8)fdTNVQ(GU=6NNkoza>wEUKMxYEZ7gL~dfes^n!c(wGlSv$_jUjSC(^C$+d)T znDF~f!=9s7L!%b87&od9BEE*&sv;qtA%;tfO_=<4b^${a49L}6KH%{xTgzw8nmpr# zPPqdRHUD1bLsm?LsIls7&A^ zW>0l|+Jsbd1u9iuFv4Ya56y~rsP%nT^)|cjPy{H9M-i|L1eELzgYza%oHQ-z74dFF&ctdDg>8QoN&0kXpvh&moSOS4kx*`f>E|C6?h=p$3p z+NL1pQ0;S zkSR8Ctdf*V2jjfmE|P;w74a@-k*g(4W?(3jSN7@^2AcID0F?bWvpiIS?`OJcf)wq- zD0FPM)soa5D-qZPBg(RrQO9MV)P#QW43K;60d1jP?e0-~_RW8?X&R#y$k_K#9u^A2 z7pK$@?^V=1hK2>7Ai4H~|0^vB9ZStuc5gUER zKZYJL(gWU!Hfn@)h8_UiOY*M~H<@n>XSKeVwe_3--qTz@B_-o6BbMSOtDErSsRwV$ z!Vb9P9VmTL|3T4rN2j<1CdXF)@e#+pOpqWgxys?%%b=&-?~zDIEh~rlBj*s_^I9sA z+cz=3JK*6vSutdK=ClGIcSpCuk>D6A=&>r8FH*;>zq06^W~n&*QA^pz^32_69*p5q zDjm*Y<#?A)s(y${Y4|>HJzVX?gcjS4OT;<;wO{UlLHo>jIO9Crk+8q3?3a$)%rcwj zY<`Nc#Iq6J39=>~`)$Pn)rxZqGpl52-Kw?5{T{OzwZIWK zQkGh>1#~S9ei(kh6@eD#0KGfY2u)qX1;mi{shZHX7dm>EqrwTt-Ml~BLu;VVe|Q>- zn!_cp!TvLiK~2FXJmK5(qfE>t?t+Z85_9DCjxfM{33;3m3$c7nihnulB&mNEX#c;# ziiY^zM9Cf=uTj%$b1_quAqT2w9eo$m5VH=>g$3@SuuCzoL;~uoT%`1^w2>!^!8F19 zZ*&PEo_{F^PD(@E1#8R6ahw2sk)+~uzq?$D&rRiHUL8C)pNp2q!iddic_@sHpq>L% zG0z;C?te}=Sk(7E6c{fAXCmC20tT#B)QiLAyFDbK-#nM2=S5ri@$A2$>lrscM|Q?& z!F5F`$YCS2f9ZTPhx@4cMW1x-x!#&Z;5E^gy26QrwCN|T1m<5b_mGS1+@o}3pCauP zRDZ$Wwq?!K1vPJfnf~5yjqXmf-}6BW4(4DyRNWW12{lR&T0kVtROOVu^lzZca^Hn= zV!fQ`i6mB16J2C9()7cH7+u}$iT_+HGBm=tbsb|VfN+`y>*j`6(UowyN+)}H9W8D% zfEeT>2v<|c$ZOd&3MU^YgUn81fWE!oXPTn$pLna z#j+g~mQ@cwD+=0>;6yZMhv#M=ZI37O45CMQqojR1ojo^R-3{dZsqA%nGV@tp=_P;z zZ|?jhPX7m4g|@}c2Y+>hommy_vswn`+$t%WV=HIQwI-BYaejhd3vAAAZYA8rL^`tB zKO}~V60w`LAZ~^TKg$oVGb%KKx&~!DE^U$*69ZZ^v|0y4;SL5l7*@{YNI!qD#4XMcc7{>(goJA%7 z{Y9}nZ8*1HX^bQ+wArVa{0bA?ZyySK8Sz z4LaaUnK3M)V~@`z9V|%Daz;dFAoz*?mftt&031TF0VFXMd;5YYKu+r1loo7qdPEzy znzx0=gb~(6ll{X4d$&MgGxQ@UhRU3iVbihq`3hv!xcAUqqMSda7&5L$`ZfBGGKhKw zY;LG94lD}!5Ru?jQ&MchK_j1fxgpz?9B;9RN@FBXo}R2l1O?^jRmyx$-hT>R{iTHM zvCDG_*jrQo9r&KspMX=Q?=N*E;3;I3CU6mY#p{C!=si@2#R@MMb(*B| ztWtFzpvXCz!$ARP*}MUr8x5NKNVz=|pvG}=WA=?Wc(afp8tZz$e(DK>%?22a4|)GXKxXZm$lnNUw-x@@kCq86b!5k@!H&UnU$;=P}vBlgV z#EhFen4)kdi{-QUSRct^c*|yzZoGAsV#?! zu0HBB0YVL_3PS4WXy2|WMXX0%^9_loh zlluyE|Gsy0Yv4!G+;u2(L8W33&jfqf;ZN!zOD2 zmMlNp^Ll1X*=mJsIKG6PKKtAqH{Z$k$y(xCE80p3(VqpoEvIQBlh2Go*J}iLH4jDA z;hC-5T-Rc0=_R5~>ib@C$ZSo_9%t@bNk|4&w~jc6BS(u6D1~Y?#Og7A z`HWUQ7S$}{QQFt8w2|z<(GV}Py0BeqIgA?=#dEIForPbq8UA-<=-^F$;BvN45OD)f z36Gtq=aOb}iDv<>sueRYFeRfPIPRd&rd7mqTE2*~(BS;>H5U ztw>za&|Zlz(NDgDn1%8Tf6tKFC=-EzA&03 zjl1YmZTu=9YoNpxm3;`Abl05)-xVwD{d`a>$GX7l__XitCLj{u&g6H}AvD2Ojs_UE zdJR(x1-!kTVdvXDyNDgjFh6Mo<%VR;o({z0F{Gy&hS@(K4Me~DWN4F}dmUjm7vo)e*UA83u_h6^>j-C0Om@H-h= zFrx&-0p}oC+w&AJLJa%(6zw8rOTm8F(z07q;s>HD5(q%~0T<*yK>`Gej022!^ux&u z)k}fQ@Ktu8nsvP?j$o^Sry@lGKtp5VQVi)3Ae9OXDORUNTD8k@@oKnp8uM~%;|=bS z#eiWXr78(M`+AI&g$Y?k5&}5pn&Rf8rV!PfVZ2s^cZ*MxV5=n*gGs^ihnKHz$$iBI zi2wOY0i9S3ZzJS)0&w~Yhw0>VIK{0fGORg~Bgo#GrGo>ttZZ)DkO_^PPxt(^K%9-9 zZ__-GAaf2Er_s~To~{xF;$Pag+Bwe~fT#{$6VDugW<9#OlDmLlg)}LK37eJAXA`>r z{>TV2h0KflO@nubpPe9idM)mjs!MTUe$Ms0?JB#r_mx8$GMpKzij#fNc^wqH2t&I; zfiVC(XsYHKNjDl8VkMLiH z!J@)B`$z7AydNEU?YMl*Nqu*~J{fgba)(fA0`caX&5&ouXPEvl%dIcUFF&gj>f%?Z zga$Oq;|%W!0v$;A_6O+>$S{YRVu%~o-K~3h`Prln(L1T0Pe>F~#OaeI%)Y^tfY zAU*h2w&@`xPc7-F6q(J7i!<`u>I3IHWa#A%Gx@3LdjLeW;UoRcZ^CmpVnGM-g|jwA zFBd8u(QNv0rQE){#2Md>SPD~Zz9JryHRJ#(KdJSWs%RP9EK{g7Qn9O0b_Zdu38R0q zGvwe0Qiubc1$vlo#_vswveUCdt#YIUk8Sl>^5~^f7Z?=XG7qdc4HdC*o*~=tUg^|V zhdG@#J=n|_u9_B>&Wia@cA^6UDbON?M{C9hCzuXiF#BB6@6=?^bEqW|gwUHE%c;7IHA0}?5EXr;ifv-=9C=7}j z4#a!Pxq%|W^~Da6yXcz;@5(RaoXfCWD3D3EC!kv}3nSRKfTV$5E3;LgKCfvYBvor* zKD~xu9D>|*a>^JKrVYS6A#tGamcBHK6=2#?v;R{_s^V61#2c!gMcS&xy$^UjyNGJj z=dTUFa38kOPte{c)pkBtxefE@RbvlFNPGm5lvyz>X zJ0;P6M6gXU;-#VF91h#LE*e;((pzl?Slw4i>6aT*39K}TO5k#7>l^lpP&F~i^1c#z zG~CK&QuN=c<*VC=2uyq8R42AGhLK|XO(pzC*Qt(6D@`jgSqmNxmT@v@y?SHak#=rV zas}^JnEM7wDsby%NiLCR;zeM1ilZ}ESA5E-I7549z?p{br{^V1qKR;_Ap)|{aeXLy z4=)YvPp&v@LMU2}w?gBQYmIGdZv<)X8*?f@OH?hv*j4kO1$nlSXLOzEDj7}#aJ^ri zqS2=&V^sWUwqG*^v8z?lf9j8ThcW<{{YjJtHyKHu+P@Ebugjg|LQAw!d+qGYtce^Z z*cw-G3)Ip z6J4PAS;iYVfgq$tn^v8KY4shB?$hjM5NwLd&ZUp77%|D1K$B|2H-M6G&((fBsf92Z zNzkyxRMXaWaZ5t=r>tRUZb7|X=u7~T?}!nKTa`9a z{W?ivh=;_Oj!#OI_%yA7X_BG>x>}4Z)664zk-M_w;&28>3seE*yhhP19N{6GZ2JlG z+UNLbjJZt0H#)Y}7_^Dzv2RJ!Z=K->|>ze0G$J)OcziYn_E_ z^aAf#yxw?W2K{d_p`+Da2ZqKh+WA#`C4aDXS*6G)tiWvBm=sulO1AjmDO|wX3OSSE z#oV9RJfOi$I`6)AY~e@K)usaEhOgyX*b?aO&|@mig7l?PpHW}mW}gM-tAM;4R{n6Yrjx)X- zj-C@m@&jFj2&K(_kRWd!(T`=~kNdkrZY7vz+iLV?j^S@-j&^=meDWx zT^YZV&x)k)+uv&nBNgZC0YcInQFbq)IjD~;*iluC5dJE65V=~^9*eyTfY@trBSofL zvP*jsTguTJQIY_wZmG)eTrUOyg!G(Fa$_8+S3~tln%>alQ+TmvMR^TjaiDFuS?r^;2|a2N`Hoansy|Xs~`k#iausWo!uM=73f~fT#!7PB1x}eaUfMBz0vIy+Ew$ z>1B|48lveR?=9%8)~(q7kNpGrHF3wRW7w<9Dbl&E0X`)dIGX+*Ik=L;?2m3b=^53S z-60PvKR%!K@k@!1Fr?yGFTTz@aAy#T(#P=J0wlt7{IUN*{41jF?K1eHE4885xA9+bP=@98aYLFC%-sbMBCil!b#^Z^e0= zzam$m-;r`J0W1vB9z(VhB5f9Jmf?kVtyOtu;Prl_f7cC$Dr&$RYZ@q;8w5?T>@4>4^3w^XAsFHX`DiglP^$-DC2K__dXcG6%}Iaw#pA+}rR z%WYkw0JhTLblTFqYv=(%`Joe-(s7Fd>u_Z1 zv~!Fuj4R*jRQPn;Yq>rJmGz|_(_%?TrX&AQ!?ZOaw=2Ns+!m|${hwnKde9JHeItOb z0aTDb;5pH0)O^m3r;yYrehwSHh1Kb4a)});Aq+m5>G^$^zC$)Wz{TaP^uWhiNo-n$ zJ$|r2)BK#cSf36bGjf3A#G}<|;#>WBQNV9#6+!Nrek|d59FtTa>`tTV6(aFm!JT;! zX^(jHXWY{524m$(KuQHas?F3G3o&gE)e+`@eIFjH##A8}6U#_KS%TEm#lNWwbeqE{ zB)+i0-1|DgUOENzLJqLXp|T%NgtOp}ICCJC*8Jt+=Nfc;^HRLnIxL99G<~KEMQQ%% z3{NL1>ty=4od4hY@4wwO(>+2Ux8~HVf_wk;U{4VgQjM(4a99WLC#2Yj6H~vyp?BM9 zXe4QN&~)bqF=8Z^3?GqPMR+h!r&{T1NaQocG*jQ*F)YTTVqQ|{ec-HzJQzOfq!c|C zn+2eGWQ(Jbw5p={P!OwJfcRJUU-1jLhRj)cl)nx&q9Ek7q4ZLCr+lyS#s4E~{^SR* zQ}@VI?yOkJTl%J(JH0U46t z{>fP)qR}vrD4CKR%;>oX)%y7;9YEB0>uZ$Z#YGkRI~m|sW#7DTtqi-&Py5L>y6S6T zJn6gR6edj>o0To1A2iapU{Cue4LDWP70GFbfsl;dnh z?(7(ssMH=`_q6xu7rO4IPAn5;aLR`J0uE>=KhigMK^repd_Mrb0h*=@ zuh1)G-cZ5}F(nG+u+O-pGGqV+j>x3CCZSGtq_W0#^Mg9(y+2235mH_U;S>f@o@KRh z%^LMmdRx!EBHs|lF?ENQkz0g%re5~`y&yvXuGfRn#hqS$vP%7zqTXAAc%eKf+G%r3 z5vS?8i+p$ZasKcg!Vi-L!UpCoo9Uiju~-Yo0i{tkW(9N3g~3HkcBq3Za0Q+Jm0L0` zQev>7EBcdziXp%LwYXNEH44j!LC)BUk zGj(lA(Nhw8SHp;Mf^*m2%Z_F1YMJcgEJaXwACR4{DSK2O>LUt}jSVtqoIrZmi6NVg z7v7EjUyP>Y8=9;jlF9;{{T;#uO%}1bqWOY4*Q5bsC9xDENpdCnaSvWuB%yZ0EIcA1 z4L@1XdTU%#Y=y9s=?DAOhe9#_VqRRaYIgoLI@Zm=5c4slS-p!x9Eid|AbL+ zB|W;lheZ4ZhM5mi`ahA^UfKbz6@-Va!(i~c0fU zhlcu+9s?pctcW%n8*UBV_B<=gf0G8OHIzfcL(kD-xW(b=_Pm)Ayqd}y_zWzq2b)IH z-q+3LJzF@2vuOYQWFs*#5CXK+R^wXrDgj#>Jg2x?2af3=B1vnd{e^a2Bvn3*lb<*K zg$1%Q79G|fcisZ|xS;A~N4gbJo`RH(u=Ae;4yxlgiMeD!vFPY&w51YvF;+F*8#>n% zl;hc4CsqEe1X_1vN_&tT^CqgDT5FsBM)NnjEOX%$WOlw0kQ`q-PUz>^c$NzLOQ)88 zv51$$G!avTtN>E$96KF-Jf3U-H$`9KemAb8W|F=_1^4wtWAgHI`iAEl2VB{>H>sX| z;A2esDrTMB#wYTu*g#o`w8zJ3%j|xeXqB=099%=;=QpNNsch}PTv};+KefL^=#F&Y zuFZ@iS@lO3`cOC+VU!ez; z6|sP33C(#$Dt_E?%Bjh2n%hB@OP=m;R}mY+Vdcta-#*RFAnqU0bQbc}t4&r>*VW@4 zz|BbTKtadIhAaBxL|hGtif;Jf1ZWV=Q~yIS`ivuKEnv^Y*3Vqd`P9E=Du#_;2@iOMAOHI17NqjXVm4->Wwc{`ap=*X zp;{F5K;LL|TU^(+FnqHl|0&BM1Yt7bM#~}BmF+s!8}fIY2K*%M36JBZ9l-w3379+f z{i~dxRy4Ei?exp0fZn7>k`@byr!CjcHHFj#A6iBwxB;Po{2Ma+WKL+iU<1O-jcbSe zyN?cPb3-R)o#KE=qi+LIiIq;2eu87?HaiE`>82Zs*hzF@wMbvkyvKEGEgEo=mx~TP z2(ClDxtpjVHc|?`8%O!39RyO+n7egoNi|&s-bzq*TR+>)^MqVyVJFmO*=16T-K1Nc zAOliVBY!@PWxj#0zkQ@#8c`nX+|so=NDRsm2@GpinTS#m{{i>)c8_v?j#^f@mPe)w zy3R7=7CcZ)xzzl!ytU|?mhHC&O|B^l1}ik9?^Rpm$YkLDoq_x(I|@}cL;ItrHk$r9 zxM$1P)`3f2|1QPpWi`yKQKdyTkuqD7XoraS{H?^|B zzrrCjJ03IxC+tjOI4chVR=0&11V<4`iA3^DSi=T6;}Vu$Rv z29t%BH@flVqCKPY{F`+B1<6TXv{BtY##6n<2d4^no{#`*qV+yYjR*g8!~f_YngLB3 zsItb(8u=Krngn~jU5ENB%BYr3K;PS(>-E9wlSS!K?OL{~BUH}*bx1>$1HWM8bat*+ z^|B*tFZAR;TuSE6@MX(4-lt4Eay9# zL7*j>OoLVn;&8AdFv+&~!7U@+fp9>M!=a)));Y_;^G0m|@ZI{8n$SIhrnkYfk*o&f z6?p#N`Of6yOd0T=cYq>LC2!RNGM=<2@XW72pK8X%Owvdo?GO|S-V7j ze?kl&Cla$2Y4Ry2SCqed7VptJ_AKyzJ1uanERtj!DwrO)=`ZeRHm;eCoY^fZEEjEv zXW#x3shqZ~W<4%&T@|*5Fsb}O{qNSbrFA(Ig~1{0W)`maFc5vC zHC%Geavv>+7I8`H?M5*C0u=fH{qO10+}N;LYc@IW)BX;%V&lSaDMr_IBU6@xc1g>l zKsY}c`_Ots^athjX+NezOBe=i+F!DdcKO7=n#!!5N*(V{4^J<*k1Gs(6}t4LSl6ILp^a|ZjzJY%aYd)F-N z;u*q29x>4$y!q$g{Q-%o4r}U85G} zVa7V=%Mf`jJ8CtII=myBagZ45{d|JoN#nj>f*rHs*%kwiPqkIf47?fDWF;dXGw1Y- zuLtF$f4CjyN2J+fVM7Q|i!gcje>cOR+pP8sRp=S{D4bNU^_6Zrn%c|$%H~nHbVC_6 zA}dLee{b^j<(sq!$NuQOfy?RG>d`0)t)(uMeq4&ym6kDrj1Bbak7cjs?MT5%cWX&jL5o+ zwpzUumO3~Y@(CjC@38oP{PVcYxGT>JKta7(oH5GXAeyHH&4&h>sag2*=XM&}-g822F*>fI-U1e%wLb^7h>oz^^zc>D2O37$1%uH^ z1h%%N31FSm+nuInpMr$3=i`&qzoDPv|5MUj;TkX_gs_Jpkrc9Uz;J~)=xrlj2a4oms5Q>jY?bAjCDrvI1cJU6ERhvun@MOG9 z05Q+0-iRo!{VSp1#;NPR=vk6DWW-Z~Eghq|t8GzB;zhZP2_`mlUUxn2Sx$-`L3P%H z07Ag>5ipn-GM`x3$7?w!mohVptIuus!gl3Z$tlJfbb0>u>9MN^dEshY6S}?80ukMB z!M)6=Jb-xEmp|dV1@Y4q{*baifQMnOsVhA$8T!_c9@X1s*-o*8-Yi-9z&TI&bT*Yr zhDg>s*^+yWG53qAl6t9n9n_+Om06;eDhWH@Dyoqn_W{~_GF7VjV{aqdiWe}IjN&rQ z75&%lCYD{suAwhB-uTbe^apy#JqiC~#0e7COU6tlba0Zm5g!Ki95Q*!4?asi68%Qf7;lxa-SAJmoT;yMKPG(se1s7I016#1=TJrIQ#c4YK9R&$NzqlD^bG~V4F5LKhGLasx4E}w zfT}rHCo#OSy2)#df)`qaLbq3g27U{Qd!R>wjLv1^vF~sLVf%w_!{BO{Alx^-5xY}L zl0OSNv;r%U5G|A+&%D&!$V_H+GLlu5umMXGNcg3xxmh@QLc=W!lH-gy0N%U+hIi>Ux5-pbPW zX`f@)XgC8Bn3lKdwj&Ub!qc*bap438s+a2YppbFL?jwXyO-KNM@zXgOK88 zb7RuY+|w2r>EYV2j-UJZopuO#pIyA}6@07{fI^=GN8{iw;9nI2&88o!M?C&^1z3I; z=ad(Cp*qQO2sTIcSZ0|kvH^})Tr=tDEg_{X!Uk-E?TZtRIZwy}WSEM;hq|^DoG1j; z@Tf_b8g=MIZ=s;8##4jn8opJS$DhZSQ<(g~0BpI0)c{~gKcqGNJiIMfTddm4qK%b;V={y=zTZ zMwLMGU*_`HLmeI%Xn89>%szJLx>{9G?-JaihDb>nqL)OVZ-&}8R!je_aU0MCr5yte z2bf-}agk3#o=Eb{ah79}>C0+b^p2r zz3UqaX$}6iHrqdSX5?7*XZ2CuKOFjdR=I#OeNA(p+Xyer$z4;cW46I`e*TeEqXT>l zm4-#3Y0pmr2e({AX20=vx2h&W>+68(8(rwuKoXIF5xtRia68{P5^74EIH$~zrRuUc zfVqwVnMgj61A`p>+$MV!g2~dz4ZLoucw& zC_}JSw*nK?UX>oyZuxe%%i>y{)VJZ>u_{W%xS5Xp`dbVU>F0wZ6;b4mnM-g&&tz$_oT1PbdIxX7fHux0ZF5!(5Qrt|AmuN4+~RDS|Ad)NW=@OE z`LYw2maT_hugBakEEeAk&mIhpo^_1o>;D8I3CSNl(pSQ;;nN4}ko@YreYrmtH^sA^^~eM1#uMab!)(wC z;E+jcZWH2D;|gasYe)`KB+yHv*NtGAD0I4KhLqEz+kGc5WTKcLL%@Kl#b`h9T0}^s z_zqjg;<>|WLoFR)W-`+zA{4CbsntS8^~ni+c;r0H#csX!p3*h>=-<7Wu!&X#qn|0bKmC?E#+u_Mi>JT%612@ z+OznW-BLXDXsIQa898-_ir;U@@3Drt94ET*b=(4?<(`pJ*m_goH*iyA{OfQI&jZosgio-yB1-ou z4_1%z)VBNg8LBed-dtGeA4}w+_FfbB<6g~tKOMae=Z-$c=N66_2?mU4F#5`Wiz#$P zg6aL6E{Gmv$>1o?&UaB2)%`r zd^?Ky?Svp4<2MUcaO9-IGk0Qa`Emk>2aR3`4Usk7bb&5IW>B=s-~RM7W0ZOw-KaN2 zILd}>SD`QRK*)&`+Q6(v)%{4Nm@Gvwu!t;BjcJ5O%Ta0v3oBuoc-sncoUl{XP*y73`ai18r)99BhMr>9e|e5B2cX$bpNqf@@t8 zEp%vi5W*tv4MbGY@MFGz)SQQ_l}UJ<9lsQ@K>Ofe=o=3mU|cj>dX59veO1rY83!5{ z9)>F*kBEpck({Nk0-ttkxTa}5j4)OR^E$|5qN6q7u>jR-i4$^&?1jt>eX^9QopOsZ ze}0Ii6q`b_!Z0>1cWE7F&=$@m9$|u!gmG@fpJmkV$E9sIXo#n^dE6ZzjCVa8`;xjK zzvE^`8=zYh(Tf0$c21QTLqnoD9@Va$dZmk}h=oc~As848lb-?`?`i!=Lgw5)#Mc=P3S}e|-3FSdj`O_Nk z@MYF}d^|x#Ip0m?rx&xXHSS1lf`B51Cs&1-e3`%o&543X{S8>B647Hk6*t5>W{$f2 zaxI&MBumcZx?h%|inEaUqq91uFuur<*;PDg4R=)CmM_4z9#{9ohZh6w8F5(TYbgWF z-gQc96E8GU((PBIrrQUth1Tskz@WMIEc!XG!#_fX{7%{&r@~U{V(gS~FV>UfJ*JFf zcF?`P`Dw!SSnM9HZySy;d-@9SPD+epE=oWNI-A;zETKwhielKdMI;xf?uTz3aWZO8 ztlAckZ5qUlWAsitHh75rOFvZ`t`@Qz27cURKh0-1W35(T^lGQSrsc`TH2|v@AbVZd zq$T-13u+tB!QVUk`zD+9vhM76<|;!A^NhS>zE@^$bw0At7`H1cCTz!7GzdbdyztUCm_!iSaEgT^s|ZJ43_TQ44~wlFE9q` zSgj2%V~z6G{z^&E7jK1{Eho8pNf(fKkq4lLRa7N#oCb;!#+Pq~ zQOMxbSqq6{##}YS1XWfKBLh+Q8QpwV-pj3GAp4&JJWkkFfR+ySfC;5%pqJbD4_t~? z_Ki_Jts+&zf}?nhhh^tZ5gj?hh04$_zx}WhM(X|zjexGKlkHoh+PKx`mi~s$7^grAE|C z)5?b9w7aQN7-EXd;?+B9HQdf8eE!HYZ+vCMVvewWL!dhK$N{(oHT3np&qC5o}*&%0110HR>yMj@)C zVAknt=qT!@Wnf0f-1@+@6aY)XK-~ZS-A@=2I_1lD81- z4r85m=SU>MBfG#o7tjBIuIQ8C;qD9Hyv6%UakUM-(b26~7d}U+<4BH%iiZWWR&4X6 z$oAUM7;1_b7tK5Vq-zj~A?CWL_4yW$My;!dV=!D-CK?!)O{j-K3tdy8Ubd%tHiZSI zY9162N1(dNN6XwNJA6*F6cy^Ru z+Zf#~CU?!n*!ZMC+1`}t{ntJvlK%h!U)aDGhb1fY=fP=C3z#z}8Aoy1c1{j}tbbYA zrwFy1E7K?>227TsF|TN*=XrYQ@WqiC8?vCrR*yZ0E)k@p9m)CgWBZpvx;GY9$b@J} zdP&CLHvUq~fTR!2o>QWsjIAbyp}e63aR346^UogqpSZ8;s{y~+!+B4qX~uigpL!WyQ2bB~P34EO@sl^qRfgh-7ddwSo5r zITHn1ejdwPkvHWrSkg~c&UQ4lbV+AruQWUky%R=5`_U#_s!hlUf+v$w5T=+Cg)V3r zOKzsI*Psew1(N*K&q3LFLD{rUn=fIbZcz96n8tfSytD*DxJ2_ov?7lC@bJdMPW0Sl z!#z2%-Zoel7JEs(BR9Kk(llD68GC!%s~U01;ZLp*egaShPDvCmISjGuEN{b2gTh;@ zSp)3R?x-KCC1GYf;|e~2_xs7dPm%{LT6DUj;G+?bplb#LpsIK(5GFOHutqIy+J^1G zM;}V+=HtgR=G3|`eE6-zTg^RWpX^|WyULIN&NMnT|k zGUYue{*AC>?Vp^3PC5<{kG71#IOZJ1ifw#ztUK0D$}6I(^Yyu0dL^D?P$p|7UmcH; z&*Xk(Hq=pY=NuTA6_YggKVZI?A_*m(hxN9aU_Dg2cbeqtm2Eq;iYsF6|F%E|Noa(} zd4L!44uHanPtralKe5#!$5^~mOWhiczm9Vl)Io6n)aH5l>_fP>KLR2gof&5E>dVL3 z1s=7Mk1W*nuw$?;7+37MMfKlZBLQAwry%uUqs&80C*rpZUd%8TuVeom9f9e(rU~B( z2GC+6zM@;sy*W2{^!0oZsWtA4iE#x-@xZ%f7q%v}p1x z-Q*3zpx?@!#KbzAnb19;TFjazh?_^*IxuRjViX`X-+2ekRBu$5NbA*mNN#z${LN3k z1Nj5J2?L&8Z*6WZyHA`pkXQxXs2;!_4DgvO3U%V%T}VcyEC5gRFpcg<*tE26Ty!C6 zqAzhMyDc-EHWokLp6fhPwGwE`MO>aCDJNI6^bo-^;sHXRYyf2C$ex>JXaNCL7&hP> z9dEMMF$ErWN_7qOPfAL{x3eAs)uuFI0h)l(3yBF(*?{|4hVAR`Tk&qtb^#U4q zRMLsutB-j_c2LtzRc458|Ijvz^N=^aiEpU?cHaemfGv~0{Yhuq;0QUl!zAWz=B*8f ziy`mboFuzZSO&{IldvSWylCAr?!+bJu5{YB$DTv&?Vt38o9rfRV~8!=2HBUwoir=v zP0^OJ|KomTA3ZSdFzu;{MjnPY5aSV4Wo6pM8LNtDUUrb25ld>gPq|C$Je{MFHGO$P ztavJK!F3==;~S?OmF77Nfvud7g5^^H8871y{tBHbE%}97lzzL1p;GRf-xIH~7aOD{30G@_Qw9sSr>?L(~(`RtRGBXs1`4kwON9j48*gI>CerA9&vBG=O`5Y zRcT=dr*YOzzywJLJDLYCBqfk_2tv>HqjR}ge6d#Tz;S!7idk5C=x^W=Jq4Qs(q~}(fVi+^)5+8o= z+$Hq6uMS;6DK9H`i5)4V=GR5z8E+>D<4$%Oo26KCJWWeqKYhyA>~W?4e1J^^w=`L( zqUqTO=9-uF#P~9cGd(FfNBcjsz=`KOeel&AFT9^zwux#PT`fO&t?HH2&Bth6DrXDWCf_5=J5V!PuS zOFyyh2&9Lut&n2TC{08@r9xQ_=`X@?3{T}R!VlCcIhv^BAws0<=AsqZMEj{y7dvvn z_oCl7b?})LKnI-+JEsEr4SFyCyFv?30iTps1oN`ji!A~rYT5&@nDou7te;?2{6gr1 z37(N?=wzW63B>osK|vNC=}?RfZ6IF;dqrq<~!)&ntT!`fCaK)E!A83X*LU;-w+& z>LWv{&_X%ymraKt6s^%9{xjMNFV617#R`cr+%`of4DK-N@`nV5d!yj4?N@&@r7})w zTJ=6tyiDd7S0|(g?(YNhJ#^tH(I2VmkL;DPq%f7feak1nAc`Xj7nnG4lx@WuUmna6 z`ur3AAXi$ixHDeOFV1;@njtFvK9~@@7{z6`_m6+ZP~<|3L{y>Ac3pJwfKwL67A3+g zv=7@+{b;O9Vnp0lk2lL|^zrMPX_Oh^t-BF27tDcb>+CmDH$#N7)8@WKbZ0 z80n5>E&pHk`vmjaA|Vl@`PZZhe?rsrmcDO$)&i zoHH{$eXeWC$m6K{@B~xghUCjVGpT7@z|n2e^&tl7sw zldU;rFprQ0J|){l`vHaTm6v$X55a1XG!B&PR$yqs`8yzifZb1S{Bw*E*jUqd8{P9_ z7Na~XYeXiu<@zhQh#{n7F0pBYa*ovwxop6oHyL9tRfbLR9~ic4n$Y=FfUv4_-*>!r z&YDnc6)rUXxD>Um&RUy``}R%D_4$5t-7|DfMwsJfXYFznb`Tdg1W~`)+${%!+&-#vZB}w=rAZP_!PENRB}jb zt9CzTmioEGeKUg35QTA_!2awqj`BCbrvmyu$V}DieZoAFE2c$hcgWjHNFvbak(fPQ2fO- zxM)TYyRnC&hC?rZwcLBNcZFLiA{4UlPfeF-lH?h#rh_+jO#&I|LnwVG%w=lGeJ6$c zE%CcO0=hZ4Twf^ly3d z1%#rcS0Gh4k31s_auFXPOlru&F=U^aM+KaazbpX=9*e^j4JN&kk<;#ZX6;(ft;J4=(&)6Y;ymKxX>^BY1y|6 z7Gj|H*l&-tgL@^Q&B`sTYnV#<@fn!tQu0LUwrRCTTW1++R?7>QUd@4!xN^ zLAf9mfZi6RC#VMfKBo;4G+{6I0qN`mn$%}s{sOY8a0eyV%%N3cCW`zqTxO?fk?pua zQ?E=YV}U!QndTBD`Bim2+bMTF_1nDp;z%a`Vu+U?7mMY{eE{2EA+!=^-MGCsx)bK| zW+#npv2}i7zKN(4 z_jDXtA_dH6h}?Z$6yle#vg@V~K_LW`{GA%TCCrJ*hW1hDccKJ6}(HvsWqsv_f+J#Vr^&ej#< z%klYP>)^8^yHY9OZ$rT)`R>$diJ3}vm0;E-DryHK28x+bYQk{Ym|~sP{-QZQR=?x5 zUyLQiv@WU|gjr`$pg&$hf~mY1>y%3Vqr)bkyl*|!Tk{fvtyys6!2=7=bW6u?3nVYj z@I`^iIm(wb2~bq=u;n#Bk=dmNv2CX8CYqs#U#{W!V|K*5y+_dNn=CPptYRtS5gK{W z1HFAg?LyqNa>Hj!sN*GRzr~Q_%Ke9} zY8!7V{C)*iv7#UvVwLrNZ?)#hi#cdIM=7->w>^t9C9s2cvm+3vdS*egjH?z)CI9LX zk5GoP-(DH?syDP?+%(g1jK)NZt@2NOGQd+o9n2v0&H|XEr&MEwaEIZgJu*Uy1;v^R zt#R+btmxfB?>Tbjw71cdBbY@0f%!HuSrGe1I^2Ph$O{&h#fE3cJhs0w$FgbHY(zo( zzK6STg2bB?RB=~+Ss$~Ut2l=thj`<;>DyDVxNblI%I~rMhpKqLaNkP`SaN+9&Ewz5>tldf^GkO`izqGj#^D zJ!3_KEb|`<*x|@r8v@7en>wqsVG+nsZVOMd(5hKg(23cT8ue0JgIt%^Ju(q(Oj?9D za_UA!P5cFtk@MIpy#NTj1U|Q9Gbi}@8NU+Rkl0D*SyV)*XV>EU6(Ca`I4S+ zq<*z+C5>##(#wDuaWUG>0M=rD(NT_!zZR>x%!!W%XXz{j8RDt1a2vjn|CxyAKl2U)Rg?A^2)xBqj*+2{(a}X9@>|{9W{n$r=&a zwEcjY!^YBNN85-!V~4S(z@uqZk;#z_RV2TH)U*E#r9@h=~DEP3sG zy(|Y}0S{MoK*Jc85Yf-xxV6LNh?M2fCi$x6*YTGdD2h5&?O#Rz+B^T&GO=ZE?in5P z)1N7X$loB`@;F*Kc`*P3V;&glpQk#U`^%hq#1xBT8QQ1a>HLevX(eh;ei%n zGoiMIvD`ohI0?(+yLrf%RWQi5*8|i zq$*A&%L`gU5fu$C`L^{NlFQfpOwkH`JiFh_N7V?L0Dv>CybTlO4#AmM1YhOzP6(5B z7ET*{7=NYTrv)1@x+#kfto0Df_sA|u8V!w-xdW**C?UGemqT}yTNWy%Qf9VVh zaIr%ja>zJRFJD5K(WIB$5oYY;qR1LfE7@3`scOI>_9X6ULWB;TeJO|Dm!*BwLvD{& zl+129Rc?-o_F@t)L!Mf{jelhm$j~rtecnVQqI%f0lL7&2D;qj_oUxe!>oeX+H!Z)o zi!*66UD%rXVC>!dlju+D$@g~f&10Kg$(5T_=^`D9fdO9yF`$eX27HSW-9o1uho;tPvJ5d01`b*$>}!e}znaeB?DB5{!gPiA&_hBqCSJ%fx4Ec127e?~JK2{Gc?;%2+(;@TysPqBQINF04WMlCXqu+i zRI;8O(1^^+e~M`3FhW?9p6D>Vo|_A}F9mW9keJ3-faW7im^h#C(Kf`7f`HZGwd7QD zKs@K&1O?g+e8`2y?P$gp$X-bON%X^|Z}c6t6Pg)r0Ht+Tue=WdK$bkc^)8Kc@+ zgmP=S08d@BbIFEzr7tGo#K}d%Lr$c!S1)GY9^Nmx-`fQ32vO1AIosxTt#j&!_Rh>! z%Ak(eymyF_*uqm=M~Kof)SXOUW>q3ou#p$Oh?iZ&7uc|>2Pls!`-yXlmbe$3r z`wr$7t@J2*;(WZ?GHhpqYe6fk7~QaA4L8#+cb>w`jRdLMWUKE>)T}VRTE_%6j0mYI zv~D%uxX3-I3pOMM>q-2UfbjlsQ1=^+u2dyFZM8y$;ULg}-Q6E!p{Rpe+%~D44pVA4 zUsx#bEKTZ|;w=?{x#e#}KL2EyK<&!dXu@fH@~M2b#rPxPTn}&dAQ&5tVsPB^hcOM) z0HG)awPsVbUt#$kG3hQh#Fk9Zf<9El8j+K+Krd4H6oJxQm@24s8XVDG-P}`ow-a~K zP{t#vTfK9#Gq?;W_ixxoqdL09Mf}#gG;6*sX0q`6i-7Xrm`lp?NV%4r`u^!IQSG%Y z)`cy_a!qbrOfD$H9@spAl7Vshr%hZnSa4*B7=1e1`k2EnC}A-u@)vs+450@FL8TyB zk^+d^IVu@=dCps^i=+kOL9GGzj=;1~YxQstX7taWt4?C^7V+(-M8%VibOn2)8$ux# zyOW|YxG=pV-7%~&uk3?`q*|28^{#`;k?6kDLS%#kZAHDC=6C8zRM|noW<|azf1>A1 zElHHtIUv4eJkS;;yi9ppJ5yzVDTF?vCQD^ig(fZc>X#2GXJg~ejpW!IXvWe9KGWf1 zo_0>J2DBt3tK{euPfBAqZ|GQuJ%g_JIz2~aN2cf!s1!@unnr7JbqZcdCda1@e_*I- z#hzWz+zqciV1u@(L&!gEehWEq69MQHOfu>VlBCh z{FPJ`HNHsYa))E?esLvnU>3ZgFh2W^WOH0<0XIt>e3tsBtVxZ-zD*`mIChc{?~6Z0 zU6XGm{23{ueN#Ha2dV)y%1uJr#UXY#<6}!1Qdm$h|M1XrWcu8P@&q*T|0m98ICGEa ztq2;-%In<-767wtx?>q?310-Y^Z6ep^#$etlty?D6U#+>-nV-F{F#kftx;#x5u2uH z|C8h93r#f_Ep3tMxnqJ^u?888h9kOH2|NCxNO_KSIjC&KlxXHdSdB0t~#((-u&ytI!1SZm21urtP2@~VU`ZsKv5fwS4+-2^}`ZK zL}N)H!Un_1F)(%PxYhMa{Yp_6m)7rkHugH)y7l1Zuar-r(MmUZSFLJX3wWEtY{2es z#2d0Tn~9U!jFV&Tx^A12`MXBcT2>xWVsgfQ3Zc>y>kH3_ee^n4h#~z7+!s-JHS|{54}u z^LvG`@f0+yzhO)2^lkiAc6+6F>=d~Hw8_}4Dw9pRnWF(u@ktHO|M4{&Oi^A^%$OFE zIc%zL_V+6gb|;Yk>qh|-AOj{bfI&nRuL7ezA;9eQ3fUAAB{IYtk9GNo&kP5P_igrD zt3qM$Hk#x-w7LnS9F|)Z-Y0VU#fBz4Eavjh@bL0IM#KSn8lt&k}V zP*Lm$#iE|qT*~81zao-rnm0H}ksY+_i}P3l6niN>{#IBygha@2V7$iL^zXdni-Geg zge7pFA&k#Q{y126DBd#`;x!+q^k63uaS`Oc0nrNHz@PiX+owB;9#vVRF*|erj+k4- z@ay3Cg#lA92?%W{Sf}Z_*pGv8L|_)X%cgRr*~hxyO}FFW9#~*gY1$YgfgCcvmLaHf zzR$9pfpG2&1IQ}B&5dPse4?xW?$W_DrhZ`^7e|ebYb5Yqy+6q;vi^fb8DRQUP5P^C zhJD;C?kgGG`o^Lze(LUiyBLCF3`hgtJ@Jv|Q7iN&b!}6iT)ol($}GRlBUmZ@(EwP& z)%d~%Vocyl5(FW{6tx_*)QhYRW)S%a&8Ex4xKG=7ak$Au{tX^iJd2$N$FuFAkpKV^CibN!V?c41PUwyh1FEwjW_k(%-QU^Iyal z%eIC(Zp0E;?cYjnpB{*^1br}u=tyWyQgyfXy*abcxiV5BV%+Zd(s#C|c5R3c(&|ie zGsiQ9V(U*+c`wv~(b6}pakPTVRYs31Izcoy3)u?RZYAev^mSXHLqcRlO1Mi7e1D$$ z2h(fu*;ysHW9s*6+W?Mz&7L&_uXXAR^-5tBx>*f3#F(wk8h`DD%wY6=Ir~zu)?|FQ zFmk&24~}K6Nqe^pjG=-~3Eb#TFD7!K(~JIZM5JNG;Ob#dJKiO0J}S0G_^=?_477Ez z?1fnrt0o)B2>t`hK6YgefUnZDS2bP>AU$+LtKZJF5c*8yGCdu;lnY&lLJfx1FjBj( zv!OKS>Yv7At`-lt%%)F4o% zll}VkPK{x>(Ny6LQSC#RbD*!6nXrf{hHjC=>ddI6_0gS4n`(hxTowmO9rjt_uzO2% z74n|c8TQlc+K4O14=ZZ8Cj!VCuc4T6OEF$~`om=!7`{E!FviPjPnTA4GbxrB+m6NY zRe$bpU4VkXUavz!!>Kw%$cps4|Br+LMh6n$HUu`{gi_J=lVu}lofG3tnAEq*B2!!I zi-*R9HBq(35aQ-%q%8!66kb)XJ4dfxzLmz0EKb_E;86n+W6C-&M*uli?7>NZdtN=L zgVr6gEEfT?bmMpG#bMX&_&^277(&s&G(e87uU02H)wTVR=tjyl$WE`}>5AMYNvt*E zeFe0*C~4m2b;I6I+6IHdvZvu~_~VH2j8N}F^zZg)tB7lzv6>us( zO7u#BuH@ft!WkfjM+Fu6on!mU#xZP_eNhzy)evlQx#ob`C-ssr0RZtrwi`)tYI)ek zhi)v_2fc!BuqR*dz-#4TjcBSUy|mQ}M=kX`MZd1Z2oEzZ?<=wle&4U+5X*Ts;TvzA zss1T~>Oe>t!2Pxe!7Y8gms|1Nm$Tk8LGt5Lan`S5-4>S4oW}u#Mw5!Q;))N2dGmm$ zPrZ*+N?eoZveH^nn;6GKqGJ?rx?`7(;|Z$qdh2wLiIWh0)ZeEgsU`J?s2c=VJ0t;u zmCW3*O>b(CAqF?oPk9}$K;lD#9V1%{S)S=tuyDuo0kh1E`Ry9k^Qu^h^gxPBALJ`kf9-TK6bKyv;n6e*fau2@#K`Uyz#RloA>5fze{BqisarOdB zVhj|qY^II4^q%|fP7sK1R~?1xr;>ADX7m6S>PyR4EnA?CL$y#->WDKxw$KHd$c-YJ?Gm{yHR}>6 z?ovG*X|_-&DyXjLVss`(yq}n5wy4{0UTq;DQ_heU+P7;{PR!U=Wo-KFQ{B;srH7Q@ z49rP#m?QeOz$+O#?&LB=8rVRAm9JxS>9THFc*KrD*-Cwg={hpzpmjN^p_^0I)A4FR zo`qfuZxZ`?fiFXWC1TL557w;l%SkM6+|~MJj|FUgotzIhtZUIcWdsbOdS?z~ieuBF zZ-&@#Oy?ZaPs7nw6X(ANoklxroVh3bZEn#tkL0e&2(Lj&Y`7Kq`9v!_Xo%M%NLeXF zJC`9~DX@tnW;J{+Jbs3>J>VYmX;rj&!Pl`Vwz)Z<75V8HOWs@EWCi4Ka;#tA5dVQV z#G{7n9;U-Yv8SCsKXfK)9Y~L5n{FY1R8voE6m$P99%Dg$Y$v$meTYPdmbd)w zzRj{XIcG&vDRpkrL*H!;__k<-!E!d*#s6SB#8y7!OuVh*WWAk)!ma_#$6J!Gc?Iw- zSA3R~T;S(?IN2X%tZL!tmI#kyCBx*aUv;80(}z?x(!XIMDbSl#qxh+-)`yat2|uX& zZ6^FrK@dVB^(c(Y>AT*9Ib8xPs7rT;7`DdX-@Y-~GjD>Cc1ZM>y(}%g(bcNU?jd-F z-nR9O$$XAu;|;yizEa`hO^m+oqejOHbNq*j)&BwW@w73V5k!s|89k`M2LZTf0a+V@ zVGJR0*QdxJ`y#!+{+0+BKqjEcDhEwd>;PWoBP9$gVc~S&A#6GC3`?j+Sr15(&+8hO zPpv!>efRI_1M~o;$Rre^T*iyilq$~qV-NB{J2WQ}w;@=^x`{4^z-o4GgVTKH8k?CI zK(oGXEc;mEY!L^cSRHut((fM{q1Lmy001nA!m62tK3rbT+SAm0QEqFSrOjOXi)TB- z_hGOGV(fs|-p6^99I=NDF=t5W8aNdu5uyfrtuhb%3;V`5lEjJG!rSm|x3)+an zX6qF$u)dYMUkZ;lf1(lRJdv_!^q!#QDt=&zS~*C^zkCVjnzd(kKx_TQC1*az=#R)s z^zRxhW3Ok!#Ix4U&n;5IjVZ$(pH+MDhGx6jWJU#3pNk##TkI$DL4@_z^Ohzj>KlJQfTE8o5nX1DDH2^Fua*_#h9QAX%yxr53-^qizxG?hWoFvbB-j`ED} zeg=h}74AYDzI^M9N+f&SgpksJ^mxRCs&LpA*gW%&Z?}ls-aBr?CjP7J6#?46iU((~ zl)Rl6R8q=P>ThpXd+YK`JQX~6vSNkInex%KdxLb_o_qf%W}@IPJ3&cw^sSWpg@-ag zDfyBb2}DZyNq`1u=>A$?tBsb6osLcg;eNEI3%)_^;tH_3&3@+snz>q67vs_;%w8QB z;UnUhee|d-m*iSWT3n$G2t2pdO0l_qvQL_pI}assZ#W^_it^nrg9x&A7Lo!zf{=`M ziddM)hv&yw7kGqP=RUrqBRMbYHxV6l?4b8lxFkjbq3`NAwX~e92ITeOB_T(qIh4@j zRB6}uT~gG>7E#m{)5;bjx}EZ{Ke&>JF7X{VE`%gx7DC~jOlU8`0BI~Lj%v$rt=p9v z#;gHFD~oYWd_Z6;QlfWFKl>Ue*!+tf`2XC-NG)~2y@IYT%lcY(#}sNLpv*BN#J#Y% zBc;9cl5m#k8XU3Entv9xG~l|&%^5hVnq)L|jRbcd3v71HT`)^NeJY6OR}dzS*DxTj z`Q<&1%(@>EK}jw)t%P)73lMPZ7c65>c4)Y9lt1&KYeCl8BFfaT#gf>DALOM@2>pz> zPbwjapxAck`joyA6DtCr8)IwgsZ4Tv)ji{#nNzo_IG%4k=S*>WGYOep{E7eUA z@7{coY0}NK1S60yJphNQO6Cy2aKE6A?3kB5k}P*zh+nd(9U2VyaK>5TTBgeBWXl!F z3svMIL>w;#gLXZoxFx4ci07>i*Ps$fB(^0nc3^A_SpoWtp|-2Vefu})Vm~s8-u7Tx zOP+?)JMyVCo6E32bz*eeOpTg&fR1rZ8F#z?Xn6wFxhwa}itBT@Clw%1tcNi8aIOup z4UH7KFs|S`R!u{`xJ5uoIhg7$9-zQ)nYK#e$OU&r$;HJNwuU~_SO+HKA;ZgJI0v84 zutcWuEXP#NsoT&R*zRgS)ha@&3uys5*(mVk3$i}+^gEH{OHcX6y0H|G;6{cd27hTC z>~o;xhA6}#`e4+`=ftT9meh`z;lFQM+a@0GOwF-@3Lgsdr2zt;$>U^f0Kw1ZxMzf# zSz^eqyXcIGMyUK|pHuS*Jieli7(d7RY6mUaY3 z%!uoI$H7JwkELuf$sK?(c4Ah6dDp9kT`u+iuHmep%(FG`Nvklo9%lE>N3{JbdkR9bMmTl=$bFn}yZ= zsc!CNWY-a)0LLJzu4nEkqx0uQEyyF>8vOwG%EhUWSK)eRd zME`HG>*2M%#90Gm=$f@la;*Oe>St-|gp2+Y2-k3sR)-(N6RoNADj!P64N9C^m^bCi z|GdXel7T>mmn}hxgnV1hE5j9H=w1oi7Vm#BbW8CqiSsNA$Vnx-@30a=?^8t({{69D%RU* z!sgMx!x>B1EqLGGV#8Qu)cEhz*2(;H)ZMGntAl`+lh%`~{hZO$AopgL#Sm7mJ_P~J zA2&t<2#xlp0RsK~14i&9m@&MyEi0nv{PV^(D&CnNFgc}sWaQ?$<}KB<>SP6EB!5PK z%b0uf8$9bSpKs(FeEASpo?Ht@jx>3D|IUKAUXbwGKluy82IZ~Og;yQ2j8Z0LsEi7G zqGi(6RSU|&`qu`1(ynxyLe$rWqF568pk6f~-Vb<~5!`^>nvIT86qbqGsWj;_Tde6( zp`Rwi==_H9NK_2oP#7oRA-Tp-wfxBKR~1O?d~3S?fi%@WN!C~>@<)6J4UA_PcD??_ zWwtDsXs;hJ>#N*9pIWh3{e>~*68`ctN>yweMHAECTs&4k+VPBg6_OTEptT$CPDaiAW zb0SAiS(UKfE;vo&7NlOK`(RAQkMo@^Q3B}@brl&&Xm>C9s^6UM`-Z=#nh=)pY6*S%jK7#;0qRl=xZQ9dguJ{;?(Br{)6 z&nT88nurO$m&(1!!rb*v*PntxlI&b}Bkl)VXIgzc!7$p=l8_GX9tK@EU7QQ+l#&v^ z!MZjRcKplZqUHudxNabmawMR^BM??K*yj(W`cC1{uPd$V7h=Ty@5FNwTjpa-c9H5P ziN|e!AFW5X#u@Drq{qU>)v5A!KylE6L1FqCzwKEMa20(D)uH66#e8XZ1)PCGBLDmK zy>Q+nHQqO^RglSvS#0nYKZjOEHr$@3mqO`JKygtre}`--A^~z9DyEIYRBk{osn{jl zOS;KI0w?^P$Sj&U$>wsO+>utM3wJU^O zfeePl?_t3&Z90x|*wPuXv;UPv+NA#(W#KRdcJ$hHUwIeKb7a(AzhC%v-_FbA=7V5$ zY1?>Kfn#=Gm4>fkC50FrC##g;=ZtPBupBJ=ZkAh`Io`gcr}}0(66W?jf>1h)Ai8E& zRU@tVMA3z<(1OmJ!80iWVe`6Mgz*_f_I5IEPwtfW0UF@WU>3H*+L5iKTWiI2_39=9 zxI+^vaO7a!dQpzrDm8ERXC7WZ;c_v*7afz{!^l)xt8m5J`s|_R?1E3S*L5$Pf7Dzx zAMu7iMq5ke9H6&Drw`2rK?f^={t2raxI0tIKWHDU08;RZO$)l(k;)Hacvg4^ zW#O=Q%~@QC?!9I~HU6?TRJ}vnGznobwYYP7TcWGGJ|8> z*r`9{(Rr~jRZj|2oWJKbCbR&6E#dyp_STnQRF@U+fZ_t-gc$JlfEEw7D)KooQUe%B_FiBPB_`uE>( zy4kvB5-BW=SIG)f4VO8;~Ctfw0;Kb{&DitCl82 znw!Y*0Cwhn?*NM-d}KkG^s_9`47FpRe3O056e2c_g%BT=%!d8%@qI(k^52&im;RRY z7hcyb1@_xl_Vaeks17m57}sZf9sC)+Wrut(QB4`lEIvJB&Ubd=#1s(L3dDu_OYqo_ zdZ+q(L3o+oPcV}m1@!&~epM{2AL)E4y@r`y6@8)tq|>|KY|2D@afC!TqeMM3J8DJy zTbzTERKh*Y&3!cdC>mnp=b0&!-6hMHl=pT(az+rY>Ih|5ar~oHwf4u z&j7r%?26Ec&dBozwdjtW>s-&>H|53UY=KXOw=E%rIJi zb3|-{n>REg%}^1GRuMn@BQd?5MQUSE`7j@pgLhklnl4bmjY(?y*hKr6pd%4#8fv{G zp#wU(?5?Jo{~Ehg|C6@1AY$6A60Z6d8oYiffOy&!jV%^jOeeoWZcQJIsDA28!~`vZ zBJ<;9;=Gl6UwF5vAGq|rMSgzOaaqcuI?f!*KG5}Giq}b*N-dQ5zPvrUd_Uf67XoTP z>fagqQj=hN(>sK2V7l{li|=Y%^%QF&yRJZqN9Fptn%U=K)ZDOgP~NM4HsY@k;y)E;v0YG0kQ-S$x|20 z%1J5%3FSFAl{WB@FCO7Uh{)_Gt2;Hq9mI80jQI`iw@eP(869Niuc{i!blH{uesCXNJKIBO7`f$bL z-5$wafRGH|1!Zcir3#iP$;r*gbXJnCAX7vV|0h7_D@Bm%Rl%niqmT}6C%6Gmp?A5Q zBQzYKegmjO%EDhG%^KjHYS_%rNB~$?^)y3PR17sFZ;z%E^tTKwJ~5@{%IMJ6zSZpo zx{ZuZs@r_&2nN1IukwouQpTH9D%lll-V@|c!1_5XqleLBY-6?h}Ah;>KF?5W7 zuu*ZJjIa}bWG@CiVo%dWyq=(bBC8LrN)h!(##5#)(h{Is%QQuOv;BskG=5}A7uxzr z%4j!?`T!ekUqYqjl|{U01dU&#C|c^861}U?=gn^NknBX@)H2 z1!9*I_=y1&{_z!NV`>8xGtTp!PotC|nnz`5Nb+y7YPu@@LKA=vSN*>3QjFM(5%x4$ z5Nud_-4`!{AwwuB2+Qxzcvo{=hv3LZ_ut@OXI)(<$&)sS0Kf4Aqc{b)7!!j*mi)zZ zPq#18KU14Hz4%idz(I0mt~PGuRT;g#A1<3dguqr?>K>AbdN|MFf}WhB^h7 z63SR+jJ66;8dgMfYO_i6F=={YR%Ph5|(k3dxB$jOib#+jkYBe$pyMDTr zfhGv>X+jOws24hr(EXjKJ)PaYP>2y{Cjg$k-&KYFF!MM8%(S#v@%%p7WZd)|>gEie zR=(9Q_U6dnCDIfk*)YjYo`7xVmy+=;^CsYe1S@^3BbwVtC>vhNA>`dLL`>uCa zg0)ECKjdSR3*gk^3Oy+zm?iD*h&wE2KMp6SRy>z>tu9Vu2=Uo?_k}Qsa(56B`Wc}3 z1JYF?F;=Ii4t7d4TLJO{A{O38g?lX%O^XT!e@a zWj=!6OLvIB>#D1ccH` zk`kJ|fvC*FwXJeaX(YUvOi*t(l>@3i}GX_*HwvsI+UnL4?5+Z>PYuNl64V? zny3|uiP#};iKT>vf#a~cA2YlHvNo&ssb$s8b<9Tpj=V&r&Xb;nJr;Bb?5PeTKctj( zSrf#m@|hd6G4l<8GT3_6#+gSfz$LnafMkvN5BsC153=j^dw6oaUe9F&_?4D8cY#KN z4M1Jx(^@5_qvN@$6v4Vhq9`rzvVRE93)Kwyg+uQGU?+ITLAg-bMxjiO9^?KJ3sYVq96o zrEkKnl%ai-a-RjuY|n}}e*g~g6TQIONTtBrZoZZ#?N zO1QmJG3It{rQ16`01Jwfzskr%_o!N*dvPYKDSW!1e8-acUkmAF3ta=hqyCGFidz_v z4anlCBg%~ze#JU%^&NU4lu?fDt2Uz7DF8EGY~ZV$sJQ8I9@ z3VX&J=j_KtdsBh832r2P`&1|YW3Op&@o@#Z5(seFc5yM-Rhami(GHe2J~!S3d`R`( zMCY-akZW4aIjp;xfC|q7yNo)KWdOpkJ;%tiGa+l(VYy%}$i~)Jyk>(=lPN6cEMkNaXH9*S0xDd-x`ZauFI^iOM3SL3S-$fhM z2GaJCtaF~o|Kxu~Jwa(t3A^R#yB@QWV zRW8aasPs2_Ya->*Z>n|{Mo#8Ruk}B>mLv;TQ5jNgv{nu*03DxtRGm+FmWfIFr`~tl+%8uMb6O;}duX0w>Kkv$p%0s0spcYt)6P-zyh$UGK-x zqp%y6TI_@>{eCo0ld(eW2-wm?K1KR>5>}1JA^k`tfsQ|dV;W8bB83eSI|ZUMwlsdQ z)%}xN8Mz`+OiTj#Q@!lxxzPa{aODUOLCth`R}|Q-dllJ3z$xk8T6siy`LC@6?Q}G9;F643uh>se7SdKkOBRRBPLP~y)FA$;^D@!$lS#M0xg;sEe)TF6nMfn!@J zkD1`@+0vcfK1O-&$^B<)AwH#uMP$R-$^K{V~ody%!fS>OM8W?iz6} z|3k(Opp)gWIUUq!)Vn{3Qf}UT2*yva3j?Ye_=03In!M}5P3|6TinaotcN>$0s5Aal zw>H$ticVnL4g<(N#>UC;IhImSGd^#2|1o?r3-tpAPZ81v3n7mO8(O9@+7k?^b6f8q z;SB!z-7jZzwSN%-;Odply0)8|m#pcytB+~ywBzuD0HIm#;!9Rq2n|WQH!qoj0YEV> zcF#eLFyi(*d9TmwOH#InYZNr$FusSk4hoNrDBUaQS7`Qdbd2i%flR+VedcOixLw+x zS3^$2U=z1c9ukG;S&W2cQlz!A)>qNmDaVhZw}YHzM}P;bF?T^oQ{drQzmkV88%Xdv zl0VXyj`_vPR*T>Nwy5?A)WGVGC^zQ_1Gs0!%apiR$uXaQ3v#^dsA~zu2>7#s=nUHL zA#ckjhi&Z6|1C|YPg(5zW`-C_W*vo~35caq2*Q>l+ixmcq0ErZNVrGPB3sF@NB<+H zQ+A^##$BB8e$gofGnt+AkrQ{WvZ1^mr^Q#VGeZCoS>GPuhYgCRfv$^n_`9K@NeQPC zWopTyE)J!`N?`7`3DG5pzgyUpz|uOcz7lIcqrF9)oUd${s1@jKw5lXz%TeRVxd`&DRy*EZqzaIXJuD4d zAi2wUI%`l0`{-&t0H~@bO^Z0XXs0?|B9|>ARwEVJ+QOQ*lzRLIIdt1sx@hK}-87v} zyGiWWe7HucEG^TL=eJ9pco>?xPyR;mZ+IJbr~3zoFETtsn}!_&%MVK;P^*9GD42)l zFR!RPcUWR!}^DO}1Yp`PjxhMZl-yIf`Z#c4Fl!J@TM%21$JwctA4*n+c{F4egMY_Tl$DQrl*K z$6iH-FggQC_x6vV)r)jQIQLUUf{L?mhAZ-s>b@<(b-6jwFa!x+?JGJw_XKSwQ4WD! zl4KR+_@-GZixI^>59^d36)Y9$#iE{m!tNYUbR>_f9RX`l$@8YYFO=DjwT++9F zALn#o*1TZb)r(%U+gV$s?1>Dol37HMQ<11oD)h?+EM-by83gT_YUBuA39c*7G${C{ z-)_3~d$MIDqt_M>NfHP=V3eG-@;M{AXX7cdA`20#Hw{Ini$pD72e>zDd^fi8il$i1 zz-hxpfAYz}%$-^=Xgb!){RyCtK5#5)=03KkPcJ=c0fXj6Bz41E%SG|M&t`kT$k7uJ`T0~cd3LwYXe(r+KQ@p zj$pvTTH=+YOr3r9LxVGIG3tOlEzq!n)i#(-P@lStwWnXq1m(PInFmM_0Dq?^9!Eqc#0#32AIahQ!On?jZMgSIeAX-$@hl4e-O>S2!WR-dsC9&qS`|2Pk zSMeLk7A1%)na6g-5*(Ysy`Zs`Ul3zX;;rR%Wzwzm1M@+R>*cBkfYTG~L2Te&Sr4%x z2Vbw4!DZsSW_!FA&JP0c%yL42fD)J7zA9m=UJ8QYpAU|a))GPNf{Cx3DzpPX36|NR zpzd5NZ&2ew-4p4MKiCAbWnud;9de#BK1cB`$fvRM3Frp5Nh=Ib;hS#6G(n zVLVpdOKgNDy*OXLxsJXYybnE|XFAi`P zZkdC?9aU6bj4FQcmPo`ktgE40@ndL~wBDK0d#TSmJ94Tm=8i3v2@5-p20d{>pA3wc zDEHexb$4k6O)hF=Xm^Ux8FT7xWo`oDx%G@(&mgD+s=K?4O4GqaVEI111(4Ycd1gjy zVj+VOCz74vwiDhCpVycb`TQ}CZdE!ibhq!!D2X1`>1uj(Q9*`O=y}`)P}C5xCJc~S zcuJMy@l<_@o4FV7_7fy$!VQ>2!NA6HF|n1Esk|}7*%)ODXhL4!Gcfgt9M4cvpEf+b z2{=))Lvj?P%-}Ql+0;ph?}R3Sw8ETxMfMO0euFhm#&-dYu~1xN2u7%9HKdTe;{X5? zb{eU}E*(gTsImD2BBy&JK%-5H6=E*Vz6H0oaTu4>aF(bpW|A5S10Wi~3*s|0D9hkW z%!P&1t!$44H~M;Z7@Vn8b*gMDvl<+rnV-{duwQ#Su?G@Oh{D+U(~6xoLsld#jQG`B z;9wWMA?*fXmD)fuVFhxIVJK7L$A6^Ol0yr+*nfJ*LW^erxGI6vjZ*7qEqtqqF9qT_ zB+mP3KlXM#!^+YA{8oGg7=7!eKU%%?Jk}Fpk3dfFy^`eYCRMn;&v=^&^1NUKaIQa~ zAibi6-YT_SzNq z@mA9p*P0d%T$V@urdrE1qz@As5d`c3;L3S2Ul|nWdn|cq?y{X?;-e{u1EOb;o-3@= zt!9D;n}3HGE}J*z9dkJ~KA89=y~|fXphs*phPNrPj6@Z=o#-i*hxWMB8UcSlciiUD zczO4GTz*k`;SL&B`IyKXAoDxMCm#r=RZ31fGRq)fbM1ed*(YK{Qfh-{2kbK^qeu7- zUvE5Tte&06IQyaIbR+~k!5@AkKd_8chx->w}HGftHpdf*`!9t|SlyX+F+;fDCp zEe2Qm4=Cuxe~CpcR5E@X;*Xa&g%WGU{PRka|%5EHg2}pSiOle93kS`Y8lkb)} zCz;ff%N4!Tq@;!Q5rzNX2vrl)3J2pliYSU#)RVF~?xp61k}OrT#~J$pMJvO9bmD#& zvU&cbZQV*GrZ*uCO`6a}IbeBws$753fKZ!GNnM^RdIkKXr!5l$nRsBnl(!Y2lf93o zz*9xymzQM}fzH_aL%s&5k;3j;Qs=Za-&#;Vx%?=_WQ1lZ3#1e-QeQGSkqA4jtQ9Py zgiIGHHMiCROF`ElEy<~7pcpoJsJ%e3%K?)75b+Q`DP9o*=U2g_fS&}BQRTJR){C&i z@MDEMH$#u%1h%0VMh)DZtel}8dYkFwGw%!Uv4x_(`}Y%U?B0|uZ=FFpWv;6VQ3Z-S zt|JE>JEL&!A+PjcWIUqXH^j8OsaKDoa-1j+Ky9^={jXd0p=c&675oG(GF>oLSX@{b{);B@vf`i zA#vC!+knI&wauX+l`io!hfzG0FANZl<>u57>fg_5TtLk)AlbQ``C4r8i!uxwQN!w8 zh1xLgDCpNLOPSsC9MgAh086a9f+&+a9sLP)bgaj&N$OqOJ26zimzfZh1tINw`iiom z?(F%=AqRWa^~xaEUkZrV&uhdF&#IdBbmO6M=~F0OX2T4|2+a82KkAz1V)g1G>mTzK zDPkazBjlT75=BL&yzm`>nRaN{B3GZe5ND2Xi}mH2C91yC!S>whhvVt2mIeHSFijyN z5Xq>PA`GO`$e)d{6&tboi2W8zcitHcZb|e&02`VH9$0;JCqgGF<;~x1HPKl(wKe;8 zgmD_=?@f7co^|M8E_gX7pK5v2H1)Ol9ns?h`S`@3A;2SQ32H@^UF@ZXD^D?&G-m%m zzVi9B8|QnI=YD*2PQXA|s2VQAlcs&?{yE}{gc~W)Y(@AUSb}iOMiSApqY`)QGc3X( z)Z|eJ@r3$PuMfdCnEyr&eIRNltjEcat5zQ^Cj&g#6qV8-V34BCpm9JR9l=lDkb9Uq z$^3M{wlnM{7yF9)ZcM29-{LDD^q9lu{vT4tr~v1k z^0YzWAbknRhVZO(+rxYRRUEn-@zt++PhEShn~)Z6slZw|KlWuWbEiP;)fY0fIXqL+ z+yYkS&F_!>*_z?OE( zLuD?YDAA>&XySr75hpP4IbDUx0e=@l#iC#ZNy4mO0uez80nMTA6Jc`Nb#H<>F|*54pQ zcjshH3umY~@o~7Jqi>DnJ-ee&feSMaIZE@1pyM{)V0wRv15LMbBPzP1b|B)xM5u_C zagI=c>F+Q?U$hGTca1zB9*R-3>nG_-MgY?a-uI<-8xJoJ{4@~zgLEBgF%MHX(oML- z{1pRpDva@^y%^1L&Wxw9p$=*U%Xyiuy523Wwv;LqfCEY(JS} z2+-L2J_vn=2Og+4`cRo%)UkdTgU3OhVR-cAujFe0VRfeHBO19@`aaVYq0sPX|3yIJ z$jEPl-Iw7Y-x%4gf*BHs)gvXCJ)hRz-f)by;Zj$${nb7B*FOJ(L)=Y*+lIPJrNh7V z@zDl)G8Q%*@gb>RwH-+dchd^37cc>-G|6W#$pU7q{B$Q?JDW(J{>ek#aOigq5#>gJGV43;|1t$)5d!@A@!K?0kT21xycMV`-Q}V^6v~63 z47ESVWT2GCtOE{6HB-^U4;|kVjWsPSkoYcbQW5*?<)I zgqYJ@L;BFqDFc#D(0bkVO&EvzSfTeKdF~^al*k&#>U&}!`?&3fzWzAAc2P9x$^xA9 zk8JTxtI#!!ymJdAPPn#pJ0O3akVk#5qx>0AD-2SI%uHCOY!I%@Klc#l*+``F|KlCN zn<}x~)#+DGfL4XvA=R!M1>c}$iewZ(>P)1EbKGQ5(D5Q~?Gz37ut!?j5AMw|JS)JJ z&s(|{^UD(E*J$ClfjesCAVjs6aMAhpDt%U6*I};4f9}Gi$Y{k$r9S!PuY?3{p3J0c zgIs+0p}u;6vq^pMUdi~HE+%K`*8Kra#k{jHUrA5bRa2DNY5vQxbo#5^BMZ-vj%C|I z7oIR5bd-*qyG?ax9HHQO2x^@mYY8qz@Q-!2I(RX<$dCmXvNHm)w!@>ttBq>uYHL|< z-O-7m^~H_zt&!#A1KHRt?zC@>;tYTw+L9k0H4|CunD!J1WEnIHAqcpcG}L5^P?KA1 zUq5%92;?UdF3lU89@eM{9?vfyOZSpBdgGj~#(}R3?QPwNsm}hNc@UR=IXfO$WD|l)eK% zn!C15sEh-6YW?Yp7RMZlOo0*mW}ucsv}JXX51g9t@vzVWfQ14vG78oxl+wOSh;ET$ z74X*_2KX~MQ)dMBn6~B2g-Jk71QPNr;yOGyaupkGmrS*lZSo2cOPWQhEqC4QnW*kj zMA;p>Z71Dh#V8i$iSV{JB(5LBZ+~jCK4|~`Wd-jIIy^-^kSi=1px z^_p&S9tcBwqP+%0?h+2o*yG23#(6O4qjrjCCGfuVl!Co-}4U+FhI zhzxEOsT+S_P&apL-56i$ZCFe*>x)6r*tegxR^&gL0*M!`1cNp|-0u1nFFYgehf5EeGVFLZV;a9TeW zd)Opz^O>(M;P{wrQW0_u@qb;yc)C6nX?RdOgLtqSL#K}2=sBQAaat;xw%XsB=W z81&<9iG8VJwn{V$eUU++uP>KbF_^nduFfKHeWcffv(r1GXqO(Xw(I0FXh}L-ncVzW zxC;5UG>zfP4^jJujMQ%#n6~LevoS=gi?SzTD8Em&3Khw#3|vnSbP&iR07`*kuekLp z=l{gqE(&K>M_$6XE!&1BZWp1sLt$9dpOa6{W_xhPanPzktSrMcf&p#LEgZ@XC8*(3 zrFsd5?H{cT4Si?~r-77G*A3R_32{&@I#r8Q+fzp)u@(QIVjBMh^|ZwVXVU^Rj-|GX zA(h6%m#a1)Lhph0jdBlBtiXGq5C(n)6vn0(j$@bT2*MMaS>)|~dNRNCkERU@zd;(FcmQ7aNj7(093Aj_esGP z7A``I`pj5O4}nCS?nfIw)L(o>CKjW0Ox|Wsa=gaS)|>XYx{$|YQYD^0BT@cdjgRTJ z4>X0SNK7J6dsjHw>_R(QCPrhx9MKmz!VtBdxcVayjbjH%I>g5byYsQ!YgYHMi?_Od+w@N~vw2!E1qd(mjZ#DNHP3I*@-|@22tpD=O zJWLu7PuYT=%*H=+iaEU`^d2>JR}!$tu*-a^oY7WwTqY~# z6Eg3bOjH!*qEfiB(8=_q{v3h`QRDc^i5La`AXU4pvdIFOYqc+|?V)Tu`M9)5wpa@g z8pJX|M-id>gPJ)A-ZHmRYdgZ9zx7dTf_ zd5n0j7)OueDQNx&XsluYzN`iuXt?rOxOyT=x~hd)nVd!dUat7FQB9ep=pFEAR`)dP z){<9`xR>2u4U?V*RvykA(Hg^ND++Y_imH{rGhlvIdX0v6aRaq)LM!`^0=Yu?+j#i} zqPkG;kNsfyIF&vocjR+0yi4RPJUm@LKc^{nD_@E;Go*W8aFnZ5ICj2nsiI3Gr&W+n7yzK8mty&FD)r+VSY*L*3Xfk&`sywvqNav zAWHE@*XYZVT$}YvUC~dS>zvr@t}G(Z&yzW5DNM?6^e`(%wR}}}my8&jQ~z3-p%Gr5 z7-uE~O%&6F6%CpKbJDcukI;hPpWFFqdW%$3W$RtuFIX6Z0ciaJKCi&*CwwiO`V{d- zsp?BEVGX7x4TMwja(O{enk-38w406&D|>qQD!C#0mEX)v2zOOT33V_G@sxD9k3-V2 zh@!JF&{uxbnF}@iN^i>Xvb;dTdB}-J%G8cm20X{abJFaE1QN$h*~r9^mMxX?QCSGa zkxIHLD;gKE_<{9G>Eyb4)Zk|h8Ubt{w}f+GRuM7eU?GzK#pLDwbw%;wpSA1!jj_|| zYW<{I6lpq-CA&E6L~WlN+e%{xf~O8Ic0g&^J&ZYh8(zx9NXv$YIF0-zS;s>3eGI(> z|D^vx^><@^vALonT6Qd3X)}(WQ65OjZ{Jr5c zY8AIy1LFJ_!t;65sL2y%5;vxocGkzC$5pm&gm>i8Jo;k3h9o<9#pmnjOE{Fn$7FvE`>}0bvKPMeXiO<%Dfjc!42@ z1@&-~LIT1QMzSRpv7#P}>d#k0Hh+&TJ2xfcmaQO6pfdn_<$!+DGAVL_#I(bGE>Pm< z5qL4OW6e_*;;+jCoUa4kt3Ia$DO}vi;(Sy;5idfQmr#I0b z9uss|m}y=K#C4X8S`3vd(IA(WP@t8UjQ6an5zQK)8|VdoNU0{7w{C<0mhiUO9g>i5 z@b8VqBP@Ei-l@}?-2KIx&^Wnz#Ym`H3)}M~DBjYe=H(s$TPL!E8M9_SYF;f?-0^yT z>hA`nF^qQa@ix*?p1vx#w3WOs7cw<=%_2S#UtdyXplx}a@{=Xx~M$bnr&tG{ z&gV?_8qq0@LZNp+tq>6SU(a!H4>F$Kvb2#jS@Jp)m>^CL2)X&k9=p+*I)m-%$xRL3 zJ;YJNcsnw4(Br_pDtq^|DfzQ4?jgNWHk2-@QzMx8ViL(22Gzgkd24$V89tbD28(y& ztgmCrlK*4$nlTbP+P(iJd89KpO>?pL+O1XXXnj+HMI20mFY3ZG(V0e=fPW2A9*F>H zxGv^AEfpC!PLVIEzq@?@xn;MwYc^71Wh)z0qJa1b_Hb!$EwdV=w@(l%b>g9!)p!;iv()auWy(cI@rWru{RwtZ|7Bz^uzo0rM=87K zcNcVE(3wS4gxMx1Ho}Ab%ncBza5{MiJusNmVbCq%Y-Wd$)abN2dg?AgA6P)ImTH=% z0z}U?JG?@-T9gFj5n*;V+AN~K=m53%{3fswvEa%Mr%R97lmZ?U($UFSH1h8(;|Ejt z8TK|`n%3H*+!VmTg!5DJOXc&XVD@SEcNmq5gxsZ(#KKFc;gM~xP*7|O&n?UOlB`Q> zhL4dlU>L=`FNRzIb(azdm3OA!tgzs?;{jiilG;@S3Jv%CVy_RR4{RJ*-<W{c$#|WcmWk z?BP#M%G&WbSmb`v6d8wI({=U-*F%M%r>hK!MOj>VVz&ND<->Vf_a%OQyeOTcdhl4)g3SYXQUqGS$}W zo^&dl6j89YVxuw7QJ44}H3oYwDpxsn5j4hsCK8EfOs*=*mhUQK`60usb9{Jcu5XfX zjP^zta;^Hw=c8bUILy@5$-bMRngOH+vWs-e{C*hVgNpPCDldgPhBJ=M053EiFBlE3 z8P1ASc)8KwmDiIXP0@E4$x=FJlmzGgQum;WVob0hLpjg|vvy3FnwFZ>*BEOh${^TZ z`AVpSEZU0YEndC=e~mPoXdi~cHXvI!#jyCbtC%uWC0w^#<jILOoNF{oi7I#{cQXyp2x<=Rdaq} zMcY!~S^TcFk@V*@4lX9~P#Zo*!}bIYMi{)xbjn_Mi5|0Ic`_iRJLG7>YAb75)OfUA zpu12N&YDf(Nmb6wfKSv%^`50v59v=g0)K;jo!5PfB=L(T0(8ToU~I5rKR6Abs~i0w zNGFHt<=a^oiTmTy>GYscO+Y$+(P>{-eA)+duX}l~bXq3(oWbzzK!LS4=C2jpAfKG% zxKe}whls7@1C6YAsA^7OP=#M3iz+T)tzD_^r6|vFj)xRQq0o<4m9oY7)s2>39^d?8`5#7E8UD_ZK*Ki<_w1T6_nBT z9Vy@+qB9I{T(@o-VVD`}2FbD@IvMLQh4F^hemJc0$w(_P(u@nX=}KkyrOu@f zq#JoB;Oq*?Aa}(XoGG&$r_XT#&)ardI(uX_{oxg_@-lIuHJ!nSv^-+e=YWH3a zbBBsAG811AYd{iacGQpKa0_1!OJ8__|ER>DfUDq#^FED33n?Hyfbu%VtJO#j;f+q( zm5NEiRm$8J`6*jR)YCq=6&D5cw?>!BGZ0s63OyCIDCP+_Ji zq1eHw$?-b<6Row8kJcs|a^xZ=gb*#Qo@|qLM@rsJw}xZo0iK`bZlO6E3L^i=o%g0` zx-OonWtG!zo4M&1%?9Zf^_~G1Tt`QnL#B=%i$-IkI?XqbDznMd%5J-@9~>K*cuR0U zeh$$3iO~IkW zlL?CH^C?tPnAh%(A;b3<*l|Pmdu2=6f=C416iK%2*Prjeu0Qvz$G(Z5QIqnUT>*^< zr})g{$Tc7kWmpfxP|GimYo|A#@7>3Fjy2b$BiA2gB17@F>P5_LD$9kNwWi6O@daJm zk97@PywSe~;?0XUX?A6rbxKD@Rz|K_paw0%Kda6dYyah=WlA)N7R*}h6tW93@(G&l zBySh#W`6=cf0gEHYjAc6vz%1!Is*sZOq#314xTg@?jxA3H5+VJfuU8%piQr)G-^ig^T+qj7qWO(#%)DFjxJDWb$u9p=0r|e@g-&fzwhL9JYc3l_b z4pH^pa*!%ST98B*T3UQOaoo%$Ij`C;e6vn${$ZMv=UV|fF-*-+R7!|Eoq49(=_&sC zRZ{qCAzIy(hs%K>5nAt6D5}X!inm-v#jy1r!FSMxh>^<@G@56i9+*brQPA}R`& zN1>Q3Jjy`;kZg|IS#TDfrfq$jpz^F7UqaP#d4fIIBrv#RbH6g>v&ji)w!&7CUzd`! z8!0H)SG!fkN1}Ul08yXh+~vToGIT?1v-=3m8D3YoEVYyonfmIbpwAkYR+)0N>-dq(=IXlJWdSd!^l4yl{iPz1L~)V+PPS~jD|`izWO#U8 zTnTi8#=KdzFs7(^_`3IUk#y}G+65_glfjT>=2&tRT{uoqOPJ@MAS* zPtJq_%*p!0P44oi9rt7@Bem2Jw8II6l_X+3M3Ra4Di$XiXR`|@ z{jv^aSLu6uPT)_f{cKK+@YS{op);Q-Ra2lf>gyt+SHuFZ3o%rgnWn_L2<7_X*NWj7 zWlMg+w|e{4*s9`06y3x-&xEoutZR3C>afznv^{|{7dG9;>Z-wY!6(3!VIX2j?Po2@ zOlC9=KG5xwF<%GCP_nZ#1D>{wgc}PpS8B8s&jr+c0P|L83j# zA?lUKt_1O#B>o#d5(>9=N1EPYG>r=&ujZWjG2s;AovstmS(|-DevrMcPp#TZ=os%Q@6Q^Y zd?!_hM6$@`2#KY`{Hrg4|2mUh$>Oda{|P+dWK7S_PAlOZ=6Gb~SUFcKIS^rmdc$BO zD_R?PVh5x_1Y22YnW*Sa%p&L))1!&Qz8c!he|+8&&IeGVb!0sQ(RDd0SN8pu$AD*f zHnA|6K}G53kQ>3qg#nKa=mH`*|LN3My^spW81u|=n5LAZrX>9YDV`yL0!DE(3{U1X zYXBrxcbnzp|9LMsgA}Y%7#wE~i7Rav$*{6Yf=(!t=6mAmI+_ zl}7_Lf`jKtn;Qt!Iw|3kBPQLOdKBs%fDN>2d}ev&2J_~;yFhv`7%y-$;^+m zGUQuF+%WF>WBA}N6xNnwAY4dG_7<1+Qbt89qWV+X+6!yKY!o^xlagY33wDB;aQ8$S zG)8eapEfdqXfwFwGW9!W1jWnE?oqoG>3XJmjT_Q=~+JTKcA=6N4?zNfEhQE#)R zJV1ZgCz|T9Y}eb!WF4+OMWuuhG~oPEsf~`M+QNs03ld?q>LnEg>|Rr;eA0+igiJ?H z;vx!x>`R@&`=9{>cCN8BUH&@&WH%%k>MtP1p88;%OBQIWT_1S2J8nMV5s}g#e=!-* zyV7y^e+ay2+QwRuQTul|O z9lnb5bNk+ht6!Pc1TV|Czl^qQY|*y)`dXmwTRku@B=pNqL1U*E@Qv2sK^y85Pf5z==kj@kSP1086VT zl0mZhHT(rJ>vo9OdV(jsyHjC*b8X3OR6r>A^XRdz(S#Mh6@W)@T2O90CJq>8BcX-d zsZvsOVXaLsg4T^vHcSzmXNDQE>p{AM!iBc$B5&E{N{)i|(@-7(@wpRf@1giFsgQrV zxvLdS%7pYqs^FMT#wdi%4eWjCTg~)s|7#I|otgF^@-OiLq1Y8H?{662bK|b{nhm|@ zbZw$_e|5__U!Pm5dGQOJqhWS;W1?Mz%lec%eI5YRe{mzLy3~pBdn#INAp>~vE92qL zI`Unm_VAyQ$@n7P!9U#RwyPp*8yu3HMAf?3ESogkaF%xyD@S%9Ug3x&mOcyZT zm*G%8-gjrsrnCC!H#7`qsQdR`4AkgUTH=7HKC;HTy6F0IsUP3*X^^gK=a#`N$aH^) zysEEf>XT(OROn59Uz&k#(x|+{KSH^nm*yN}{SUrt56~taEtAI_a#Zr39A_vL`UcNu$8>GIfZ$SsT(jt^F92HV-Phou@J*Y7pg!CI8Vn~y3TnLSr{2! zpzZ@9}}%tQ%<-T{2jx`%1@vzx*c+NoZvy|So=w{7P2XT>f0vMUdq7BeL!7(=LU^*= z1^&I2GDpv@bp8mp?)HQ0c&gVjEpk*)hwvRwnW@xjV_f08%zc=+2CB*W;+G{^qi3xHkuMP_9_ZN^TDP7&1uFo#(}8Y| z>a~KkUr^aw4W_n^hg{jN=w6NIjd8mkh3~vZRJm{%bC>T*7l83v6$jeXTeOdTAjl@%0se0Z(U+uVnQhy4lbntO`qf>qnx*gj3qgU! zcWxktEvn}V!YGCG_uFP z*7?BEdBsP;*~B>uhEPobqkuDqnD}yZEj{ND%n#Ri?q+FgaRlxtB+Y4Gy?dLmcg1{p zyP4C!b7s@;7!V^s5%vEL#E}^Zf;K@#m6Y6a1J$-ETpii~SLGkViGHu85mkhrQ?e3K zkHb?kIaIe}6Zfo3#~aSWag1T&06Kv^B4GL~DA4F+PlqaqE$x#1f9r9j_>9GLV6!f4 zk38q#yyZ+v^yOf21y6S$xwPsRF8aUv;*MV4pXK7rpi-|K7>*=B08_PV+?abDAvSn) znV(CO7)C}v^7DRy*}#bdg#_Q$S&cGc`UJ;^A4w_wHEQ!<#2!Y~ha1u5+L>2# zx7drv5*hX;f>5lHbWv86e?`}8uT5NhN#7m-e6a>1Y0GMSydlWtkJHGK+XC_Uof8D~ z`6z4tr-+@++ANO|K>WO?q@F$nFp;V$-WfaAc!sMHn0KpzPPSHdyKzFs1cfDGUouig(b00*&< z{;_6f6)ta)u|`R7nciPqN#~!a-TTWXJ$A$(Kv~-gH1^76{SNq?$GT*#}=cKBGXpM*?)SIcX1P6_K3Q~qR-0W+#yeru% zO&_;U4g4Txju5uTP1c(hu?WNvq5e&#WQKWC`OQC5eQ5r9TF_#$EM&|tz$KlT@Jq(Q8RM5(hs(BB0@yE)&D5<8-L3s~sR#PKHf|NffWObk zduQ@rX@Pc^o!@gFRxk{=hmcP!41}eE9YVgvSk|){aH6fth6J?RS;D($gJxOLV`UQ; zCg|pqx~y>M3S+=quek`9+lheOVG|WvI5T#3|JV?V0`PBS83;t+vZAbO+n-dv^t z$LtmUHn^SR=HcXm%=jQn@OewY)5~%yMS+l?B93<^v)sEikl&9*@ZP==O-e4TY#3Z?Ep2 z$fJ>IWz1{x_vqlU9$x0u?%)XukzN77&Tcgscmd!DVFtslduDq_oV2{=W$FuM;Zu;D zIb!&qSed+#cR)y>|7cTTwa7Drz}8hbpFc6jF=ZH$FCH<0`K%K?RhfK_ zXtsL7t4tKr7+D>&_rW^i+{Rp>GB-@j#^y0%r0P_#Y7e2C>8kwLR1@1PJ^MoUzAeic#^>rOnbrtmoVsXlCN#oWUmSrWtyan~J zgGQQ*-#c)>UC0eUKu@J+e=RD)l0@JNV}PW0uZ)m2%Fg4>Kli4=`)}=$2gaCdc3KfF z<~5XK6bJpeo440zp>E^_m^V=u=lvsOJg3AJGiGoTLBBg!*ipi-HT+tngYW|bSMJNO z%f1v~7H1if<9U%JmUc!|%0X(FOgi0Q6yNaOSM|r;OQ(hv2ACIrhm}K*g0h{*x(N$a9tp@_uB0%j(%XicbMG=~9w2x(_kTGkr;0P>s6$Bz zb*Bd{2>U^c7Xl@_s7Z)?pVoZi4``XSJ`dy$mD~9w^EQMLC1nPUd+( zk#&Nb4aB*#7D~rwy=XKZ2<2$YvVtnzc*u{owP+H^Le&ZIhKv#2-3nA(_nEvLPoZ1v zR_?9n2UeE_)WEHdNNkg$GXWSCBZ7Pxep*{=CzB_@^PMAWnt@(deSrT)oZ2J=30Pbp z{Dt0ve!Rquq)Pmh{3LwVf|5G=mLcjZ$*s(9&xp~=hH+pXoiYsXAq$np9cm*P&4U<} z)H9e#d+aN0zWB2!NGi5@00FI?Q9(oZqcOA^Bd+_V1&1P@+TVh`Q+mTDJ(8^5*ZQgc zTS?+~}O*E>7TbG=BraE(796jIX(&r_zYsVcWkSgQS(A-`idEo7zmU-05 z{t}|ccq2t_cn@d!5r&aCx7Ia+u+k(ODtm58xmcr@W3;SN^-t$7wJ#gi?Mol;AFD7y z4*geuu98hDCl10Z>!OCp6d{UM$;sFKw{>x@%F33+OhYYkcvY$FP9Z7hgj%H^(f}<$(!XQv@uKlP=gt*7 z1iDhQ@}v)DjfJvi`zh#A-=Nd(&-O;(i&*UQfMDacinh_+Bxm{1_=rp3<0j0o^u<{A z8kN;+aDv=!`oO0IdH7HNQW`!XF7ZLIeDef5(0o;VMEchsG4w;1+nlg_$R0zP_Nv zu(Er|@EILJC?MSSTuPNtuP#&{o8m_9Cs;Fi3X}Nu5z@OxC}id2l?UK|@5b{6=bGP! z+h_AHuR>dHMyp#N=*U3M~3OwF=5X2xf^!O9Ddj>0J`5W{ z+EC=xVF0fK(@|bFLZ7r4)wIwqP;*?D=k5^%AO(*2lO^U9MQK zb2vk&V&xbZC@tUcyxy<%e79``zgs(X7Y&k=v8^Oed;W(5Z-&KN7_ zZ5iRCxkWIUSHa*L)!N{eE_ubG*&+B6n0X3TJYHroAatT&O7UJ|tKrWuJLubgICu;D?UHtKQ0r? zn{T&}tJ#8w0<1mNs{CpA!xm>QnPCeH=Vl)Zq8N^cUMS4dG6Q!^wv2aIj8ikMK_8s! zrIA?KjzbbjXWj7+D0MwuZ=vde;(&mV$QPgn&1Ld+wg=6@!ZW2>8q+KR11WfZyo20m z1hR!0UxY@3(IftKAXcnKm0)C=gjfdN@Wz6=UF|%5My>6^{(L78LoKp+(t5pBlJK{0 z7Y4bpmGxA`B0OO;@Zp4|j8Bsd?&X1f5EQw-c=>A3a*=R}LWm$M#pi`@$|(c1%S6?~ z2U-L5Zexq7uc*mwof~GSft~lDoM4v^ZOh{}?fefulkiDcIGW&1+BOwly={t=oj?N8 z)JZ~y$bm`_G789u4EUU7Y!`W&8;)AM?@#bb3;t8{>Zh#FJi?2fGXT_+W#uzVnf4*2 ztHEuc`~9M__evPqMVx4cN&>eNRJl-q7y4ukt<;|v%kV;221QuqwaeA=1Gk<~4f^@| zxaI?DSb^>8IkJ+n_h0VYo+1oLZFpXM?;*#m)$}OKRXhLa3Hwj7X~>WjweA$8s888J zSfrM7!@)u=ZNqASxG=F-Yy|&+uYK!)=9*{@W&k4wg_}uUrY4LOZm)jc3mK~>scw$Z z(Un8@%U1_)Q=BZ%rgw43L2T$SRAMoB{>0gFM<)1ek)W!=V{N(6rhzXWGK~RgsaQgw zkvT9IXP}Yl{CFUY>lO~M#L359pT_2&uDqol!?|LpWEoR8%H>#`X3Y*b=3cNl85u4r zzs^^FB1k>$&8*Q3P%GgMgq%s2>+k$NeY9~QU_wT#r>~K4XGB9G(|>u=yYWxS!}2`D z$AC(6hc(tUa$bms_8}4em4H;ho=1hc9_4b+fpVps&w(npFIVI8zcwSbNsz`~1}5rL z-*__)L)UB$tu1dCGD1b9arjD(CzLG&dAT7a?%FUW1%FLw(K-$QwJU#()!lTzj+(5vjEYGwh;uzF3S`!oUh6>z5aSj~0*R!B0E>S{PS5xirO z0NUJMWg@OBd*E+)r&=kBCZP;V{>aN*^j`ud+)zl&;K_a`B;=E?Bp?J)6QXri>5sCB z`R2hzI5VCvrC-OyZFy4Duu_Qp7B`we#4jZv>=$~_D}K_{HZ8))EdBIxiIh&OmvPJ_ zu1+~GJnhx&ROu7Uu755Eh|{D{P+jVHN?*+z$eP_I_(IfhW;bQzO41~VO6>6h>7J1Q zGsC#Msuw3db(j*X4Y%TfK?#ibqE1<%cz=U>^dwXUogU)TuF`0d<7B$sG!wg{JXI9ymlrp}O|!(1lv{~YtGtkbfkZL<8i5z_fVU|;Wj2%2@RE`TOIlX|`+$WS_~uMd z?pfm?w0(CJ9H$&^|F&MZhYp?I=g61OLch)Jht=du$1cvIgRKzeRtDAGTk;0IzQ8wf zG|?`>QGARcF|ej&suu(hL84S_G>X%F3z1of3N6x!esoAIBOORm`7A#+k^<#6G9SNaz+4Xp3gf%~Vngt27&H#F7WD2d|#sm%@$Kx$04xg7Ht15EL#9XRXELwCqM z!!3K=Z~mHT_C8Y|t#_ycA-3y}F#?})=v`$&F+Q|Tpvq6hlKbU#-oA$dkB^g%xo{pt zSza$mCICggK3jjygW0~}&*V`a9eACkz0>m6CwRO_|EO)slVN>bTRmqdBAFz znsz|&D$x~b07zgY0F;kkF|)POx85GMe2Ks0br0I#EShe4E1N94*!h3X=n_~h!@}g8 zig1p+Kd)%XG(nCrBmo~M8k&Hn4Nm3H|EeLx=2$08>W-Pw5H>{a@W!K= z4v`9w(BEu#eIpQOC0S>7)GS{GC)q@Eu0{1>u7U1SB~;B(8-UPQV)AwV;Bcww#pE74 zk2U=?iL9F?C&oG17MXa_7htsnQN1k|#M5)L^;5tY<8j-TXsoF7F&kw9giVxnD5LW6 zeg$5DVbw{cayhPABWsPIgWv#s(op@47roBWC-*&NsZx(57r1}klwTrdZXVmcj3|EN8g3CR$1ew5mLG*~NvvfgrRk~R+$d$`~&{NadVA}3*jz7&N zno4#)cwN+NuRds*y9uvsQd5nLYns0LtnKfNS&mLyt-hSz;h&Tw4o`$Xl0w;GJj%Z8 z%`&}-nM$eUc#bL7WK5s`IC>JJlIJ=WqZV1NJb@u3gP_3?6}iW<=@{sv{vSnkVs5c! zp+51>P?J6oBwMsYrj&`5m2nOnIpstP9=K@732;&w*6*KzJySSma&6B!#T;zu(Qma0 z$KrzL3}!D^UdmoT0@>Fmx|Ab}yA+8IMKOsxxb45;=~H3#Kq8dqE5h z!G>&Aec%jlM5d!6b~DP!xffOkDwDk`bII8KiKz38M-&5~zRG@z=35-hciI?#Pt^IBzD=~0wGWP_A z)v-alL|&b81;V^Oq0l0x>jS!7pdsp2aM&ma?Q-|~=xkAE&&^T4+mz^ zHA||!lXlXGMWX+OL~bYH%*X%Anr_Np9L-ti@bpuLKjK#(NOs~wJ%UbY$V4cL{GGRP zXnCpZjRMvH_!KC(1eF^iiMRKb9XCra;{k?=>p&4!KI2#iN;EQT09JA1qX=R2YcSUT z93FE{f1;yl>$gdYwRhwGjcV%OlS^jl!1w)M1)0>*3z#{H;&E2~Xw+0}67@g5s)Ne; z;s)VyES7=igHnf;VAk`5{)nZRODZli{kMaF9pSgLrzc^NYKzT|?Y)TfaODPrB3>{0 zH(|`Zo5$u;j{;FI{k7Gd*0Lqiw*88pT#d;?1I4V#e>X*9p-QA$G&QoN@$m!qoclE4 z6>Cq;S)qeWP^4kpWB|kpVWNGpO;)RxMQszrbErtM)@N&HOYSC?b&Q6otSyFP2CQ=k zHUrG#y(6M{jGUDvJyDJuZkTs{_Iu)+k|KHYE;>AJF+7ua>=WokV(>R}7YstUwjrj- zLi%V#qRTg}W8X6(djbQk<@F-AAsK57Ws=%giT8dXv zygtVOzrc1PqN1!=s)G&%F%7p2P7s?2$-K<83#yCC1srX|@|5{A{ERUPUPl@u2@iz6 zg-vs)-FW=~REBUyYd@?ysP3(Fl}eY|d5Z?P7d;zb-Bz-XfTWDdo}`;2^ZlgS|Kq(a z(w5KS+G=i-25l|Kl{*CFYG?Oi{%zry|A4}YD^iTt+GxzNlWa@r-@u}w2|^zywE2=k zt|o(QDV~x2!Qha@)I5kt2}WK^;6PB*vwt#V-{tQ!qqNgyX}GwK#HqT%@MD>2u=xJ9 z=uM^*)L#Cz@6+$y3+q`aLs;htpV%k>Smu4fGQ{ri7ZOUtdz<~UEawfFHe5x;Bxi$g z+lQzH{5vjX`WV*bom}nIFp5eoSfoqIPou*WTn{BRD-i49o)YgXN<7{1ptJ6ueAR7lxI@PvSHWKb**!(`qJXVHz(MsAk)D(1ld|R1qmk zO?I*tn#ryAq#|1JQ5j7a1`J&E)>W7*6_QcXIEjiLIfQ`|`X8eCo=3$mGW|D4PAw`g@N@*{Ax z21ZJH?cvJ&OZT)Wpo^I?O=bB5%=c7fI}j-)ZrkvO8A)Ub6$x0vIzY0dxIw)~LE z`fr=-kDOJ`rjw?3fzI-kZ1C$`%4PZ5ADTlA_u<-q9`(z}OxIt12_od_;tf5W4)1@IC z8Om7Wt;Yt6b22k@s_Z@kMFel=$k1_V+_TqgEL?f>`79YE1n|=h?dIMHIz(!G4YvM` z7Jm9MHg5}KLZByTQ}qW37Zedqf)*}4+214|mzVSNKF0OX@nhXmN`KGf5mxG*>o^J! zBajXjXCrr*LAw&)F6U@H^948(9k{nu)R^P_4!gvnfIoaGK~A27AF|M1jCflZ1$_>Y zI2(H~?i;^3hplc8Bkm!L7XAa1+35UI?(%Dq5#d2gezXqy&KT>1<7y?rTI>9snqF?l znBwGmXgAOpMUa^pm<17W{ZJJyz1uauEXh8H#=eQU6l8@$(1Kv%>_2agK#6z|?ev9+g4kZJao7#-!P3IDSSU0d5tH52ic0K-L27r; zaoZNEA&(eH(qe@Xod{N^tdeW`UouT0&_t%u0x14oVI9f`G*5YE#_z)n3FR)~<=c^m zRHjKoCz*{scY+iLwh(?QWj4x9@Q~()WQ~Eu?1BKXU~)nmLKbtb78JX@{dqaZL7>}K zEH=VX7{66oIGYS~kAj+PTJF-!N1-jByHc*?<}zUWc3E1|GO-$zet zK3WZ1fzX$(Wybz=$aMB-$kJF^4~;Fx_k8r>6G89K`Tu&v#KI!$!9Dm}{DrrIJvrS2 zt^xPTHd}hHv17lDxyfU8rnykk80CQUs^uj09|1zOBDo&HmR!<0LsO4ti_VJYl%t(0Fqc!*31{qshqnCj?8GvFtp2F7%N9GY6dAs$X}6NK-58 z)F&i(ZK{su5uF;P=*ElDXO~B%GTZaeBa@;$0uj@glPSM8y50huOA@a?>TQ2 za6A^h`kMI@aX!k!Y1fg5@|E0CJx1|CZK;iQIm#DP?Dz zd*LrKGjPHd;~9D)VLB6p1?I5Ck$U_2O6gt65r>Q|$^eK_S-(vF(n=Be39&=E;SW6l z%j=-wZ2zoQDc_^yQZ#%+8YLy--J-(7I`RJ~^v|F#Z)C1Oo(uSOlw*cWVumB8`sJllnKn*|yZXdL#Su!A)112p`?G7;sq(TeZ2 zhXSd>Z>*}0!1=<7H`Oj~gZOq6!paQVU2SYZUh(+;Zg~D?7JZq!5uwFeU594<~^AYsxU6Zh6iW) zV9so^vV%ol1dV@_rFvwEi4Z34>VF1P z#TEYNWuY&#l48|<2X%rhO{KtkCh1e+mFqI9XtZ~UcLzytN#J%rYgldM4HoV`VN7;X zEXq*X^a;S{a58gru7`r73*{vWhW6c;>o=G{FNAL2kf{1YUR}E7{39lZr@l zTodiPtO*2@e|>IPMlZd_^0*E_w2gkaccT%wI&;Ou53)wcy=&G1Mzh;Pn&eR$4zrEJ zVQd!pH4n6@g2PW{InthG$U)@^OL@I1VlGfr;D7URgcq3oEtNkolV@1lM}#6hB;PwJYIZQTjqp(((?Os z9Qz9ZXzo3AGapwa_V@-f)cUl_^)LSa%YU`=6>l8IzFjYB$hO$vjjJCaQRFYYj3al{dVo02%Wr(Ra3_Do zelMX3<4jpGIv^uNY3iv*h=Ji{+Spb8csQk z$GONw8?7&Nk&Anzk(}EuFn9QHwIm6Ou8p{LpZ@nDooQ?kZv{U54!$WNq9~R^>$X&! zZ&aii<$6DyIj^vw{9AU>Cb7&W*dR5=d`}F-F8!7u68B#R#c(M!N*Eh-f%eyc`Erd< zHYnwm3uu>>qE%;~Im-(>m9fcHOi$jUT@@dT;^cMQei z0M6v71T3{PUAZ(Aj_V6%wS#G)SSNtJTFzibC3L*fzd?pXF*r>eOCPjV5X!Q4K1ATL!YY5La&C>i`%*{ggfa%WfJM+XkalH zBC(0?2uERvi{i`CPEfG6dc}GjBeLPhG-R7X>ah#wTrL-oFBrdRPo!rz4zMQ1i^D6D zf~tkFxL4L?GH7%POfV7ZigK@}EkNV|vh6mWWeL)+VtK+`|EcoUr|vPY|IUa>HN^v@}V*{FbmevKC}$o)8F*OrB)lNl`FmN&T_6@)2T7aOdXq_ zU`?h9+)8fy+AZtg)MyrT4F8`Vf9Cry^`K%Q;7w(7_7NwBGJ5sV(ZA;PQKhV zMFJIFaG`m(s=+SrJwmjy%ebyA6LV_s8~yTtcQ;F3;wWjus+mP4E3Z>eDaEEKR4i`f z9*O7l4%i(FgUrwA!In)Xz*T1^1%~986MrF5PIDg{`^jP(@>FX4j$)O~z=S;FGqJq5 z%Hmxm#LN62lMldOV5AH$r4p$*mrE`e^*aIW-6hC!9@XdWsx}D?G zcX6-AX5&{aH<(?{BX%$4T{*LPt}i%35Dv1G|3@GbDA9_`i2vz8Q(%X|L6}U}Mn8Dc z$Nq;TY#U_Sp<2pGCG^RMFOE=AL4hSsJqxkw8W#5!6#vY3xrN0LAMfdr+h{7hRTh># zDuI}X1Z_&`dSvXOg?#NFCe|otgP?-);bEK@l!Rw1s4ruZ#i_)$;s|Mmr|G`k4@Ask zNecwwFt6G4SW3^A<8Ymb(C;OfZwK+m*7Z+g+v4ONi{~iKZN*&|25OAZxY#&;;~&<5 zUnM%I!+`{?7(H)`=#uF{F`I)k~Y0NNK!RSzlg%2llE zc2#8?+n_i8NqfE#a$8|XcKIUUJE=-Ix88JgI+J=m%*veu@cedBRVUVVJW~4pc82|F zxP*g55h36N7(Mh`zifytfCejQTP76a*s)l%Xj$&G-m^!^{(Ntc}da zQ>8(hSjiGB*5Zys91FCamFb+&t0RjL@*sTV)lObBrCBSTZFS5LWMDBAo;P`yb}3t4 zi#Ak6i#M#n$V4-GR>hMf`%i$h_4|+E10*CV`Vmfh50JU+Npi8v59>}>t1#Wy9%BgMlO62@d}-ONp?J_6DJueP#sQcF<|H?Oc|6rB8bT7vIRh zuD<%R?vV2`iQA;q!T=zzk7{=N(|iKZ0hgzJ$`ceho3wN@T;P(j7EHpu;X@2iZ*pi> zH<&|-Mq0n>eDp-(HHTOk60&8J8eQPRV6LO`^2w`k90)->lCdW?mtTcVd3S#kmBxm;6SGDz936Zputye(4}VLi3RYGV1T(K?H8q6oq1 z2E3c?vNQThl}unWOo#srcjNl95Og$jh_kPf7emBRR=$+uA|cXI;CJ+OOt*Kjx*L2^ zc9v9{rwpTyWnFeS*~HT#pCl`Va4pCL&A4qsr}A{{A*yI4ujd!V#Hb3!d}2^N_y;N> z?H9r70{*Ep_KS4Ju5ksfPV_q!n7e)AD*|ywM!k{K{?Z%CXb!_PQC}lu;Kkwz0QMA4 zCsj=(rzQ^`u%6ec6lp&J-cv(oJs^vha9BGa&L}1$D%BgFCm+szcYRbR!vEg?hmI-R zTL?`}=Wv+dt`m8oF-~EENx^;Z8cpVb4pKxRqwM5iUQCa`bZG4(|2thJoth0}Vt$1( zk&t1fjlYiTyu`E>jp&1bWa_oy_*;&l8}?8j?010d3E3mz91>36mX*zGZ`XtRW8pAu)X=(L2>VDeC1M5Iid590xz?+1`R z_`Lph{?_Ix{CH(@ftY0h__;f9Mu`38hIwnfBWU7k3#2>b{+G>Fq`}TC5$tY?oCt8d zMr2al?VscPh?^&T>$zYRoCQAln#{+CKok#BuG^2>=lv0X?EO-XJwH!o5UZvdDDR!1 zA2ye!X6HXPqCsqA;P*(XzP_yFPV^&@nTgsG+Qu-nS>0H68!u{B2V{wQltR|n{v#RE z*xUzdKQMo=x8j!TjO%bnRn@e2-xn}r2%Clg()xyLRm6-D)5aejwYO)m3Xyc21U+0} zlsLr@s*ZUijzK_2bWZfTN%_IzKomX^i)teuC}vU*c5r{;i=|1f=KGkxxy^Zw2fDB= zfUkHAZI2Tb323}U)H0-7X~AdaAi-~QzeLgyj<5ac3eD%V{Z_8L2pu1JbIY=SsRlcj zSojA6*(M|z9VGuaD(1W$FwbWTHJkgzoK*XQIqqVemT?bU{9A;$T}0NM`{qmud&sj@ z%AG>hqR#fjerC5qTW0cqxi8H7kPpqrf#-FY$y-b_OSCK}tIJ4M=XRxs>E5n- zw+Z15WfDt0%<%k}A#h#1_R^AK*M$GsZkmh|`39ED@lkyiGtdYUDI%{g^oqY@0d(x+dP-(U zq}eqnrkUOncX+xbQJM+O(>)JhGY6GVnQ8k}tjZ>@#y-NBYe|m9iicwgHTAW3e#;lo z_-$ZTr?)o}SX8(?ah^Mhxrr`6OPI9Swgl$tP% zC@gURNs^|+l3x|3{_e&?K)a2w_53C8qAZf`4yjb0_b5DbP`Qi=_m=r&j#7L_lSZcL zgi=)pIZuC}t$f&fkJ+OKu*I6OZU{|ONB=mDYU%s@mIEUT@y>W`YYpW{vQP|EPB_;6 zJPkj$L$m-0t8pi!>W*)i74}uAb9n;H|5kc^6v-UPBA}uS-AJ83-f8Nw9LF?72w1K{ zhV7y#49@KZTP8Xj z2i7Z1k#3zvuBW=K%v`cp@dQ|{FJXD9u8^;BoB-%2zB_n382F1iD1jRapUA5`7>uE3 zjSfbP*-Urf-tmAQD1{DCykhaSud@NW;=|jh11^5FVMtOG-wmx2I^mF6uY%8b8DGgP zwre*W>liJu>9#kgQcux%HI#3P89LfO<`c5GH7RJ|h{vEP?RoH0F#og)L)2FDPh+ld z?aWa`9pJuY-el791A%UqDX4@Cn0*+bba`PLwB%XM-xp;Q9B2U<;1_ab z@>Q_l2n%~Vq*HQV(RcDUL=w=KCYy{*5jl(oYjp^{bKkepfzT6+`hsxpX7>Za;Y?Ps zK4+HR1Z9FL(wyOX)U&GImCI&t)6#+sNj2lvMO`K_ z!}xO4?(Y2U(PVvxA)~e$3+%c9=c2`=Er%2{JH<)LeDiB#OOl#b+{yhkPnmS4(WEu+ zBT<%m&ax-~xc!oXauy`>CK1zRqoi^K^V(QjA0UhW%v0=SLpun=kTHcVRV}W)D83|r zf-(Pit%0!~L}VUuQy#L%&l389#WqZ1^Z35MYwDE8hIMoz-?xZJUpLi!O?Ht&r<}YK z!V3|}SF_pKYt_m8xG`mQ`dXN(RdK0|wzi5OAcVwb`Im?u z^fY;)l^dOZ{S)i9XbU`2vT>o9^$?}Fo#=E6RWqOg#lzqof1VO}gLB_wCwm^F=u1Vy zmuD>5DB$v~O;@eZ%?3VRg{&lyUCmBbskc>2+UyBP@g)(aG^C4*t(|3>eX)}fT>x`2 zzgGkS(#T(&bZi6uxeR7c{g)f)N@JPaVX9RF1ws?6zSZBOXiqUBVT?i^CrXu-5Dl1- zSkrgU=k=88`dBr!e`*WIMb8FC&mT*&=V#?83U%+vCgTL`ooC*3^{5yHfGqeurhw7a zK00mMK~3AWPQxo$IMimo&c-0<&Q5-!<%EHpL#`*8YfrEY25d_lywqn(u5}J)Fi^tR z$G1<(k#N>uxGCJ4EG#DG6Cbh#THlRnz*;iM0DQKhyeDE9;(t;PD59sR{Q)OgZRIT! zT#Kb@%VKa^I==KGrQ678p$T?tZk^J1h!JvD5L|rEMg5b$v9ucxbsZ_bRW*2~0tS5% zl8pN{_j7&v%1Q;pw)Uk1FI}6u7j1J1)tV-Mht3kS2<{1r#n>g2rUX6lOJj`mv6%0b z@3KR$yIMz_(t3xSH7`BbY0m1O3k?3?{jn)gy9moAIa-+aasO^V1zO z{<+WN8Y#uE=2V>&jppJ-S;0+gg%ZVlv}7oXThxYkiMI$&cK^$qsw31yi>(D)0V7v; zijLw3+dxxnc~3MuN#zV-ijwPSd@)Q@lgCOPUKkl_ykYM-!f4DwlX{)u_VW*Y-s78W zoeI3GYZ&Lhzk&o4BiZvH99yHMFrLuLHT~PNG2m$$7MLDKlZ}$E)14AiMY8 zsOr_y#b7vO5MwAx_O!D3EZb^z`?l&8gVGD)o4RmX!# zzwK3BvTJL1%A+UA8``dyh1NT$tsp$t;o^wzs{N`gLX*ns!Iy#b@J&EF{>CJwBoI>E z%?3m6QZjvPz zjZRJ92EEx_& zdyp(USq?Z$yyN(qsg7e3sHG((B@uQ>kVr&|)@kJ~njlzZR1M8mjdF^EKS(Gv zpxp4QjwKld0KKDa&hi>Hz8$v&nB#3sd)q*Nr352cBY(OOWKs;fyj`wO1?2%G;%&7R z+lBA|1){lL^k}i6M*|b9&A%b?T*$*MACvsNe zS_C-jG%6HI#ZC<_bg{*|n&_hH_|xva2ZZQKMVGyiz=8}|QIr4m3+4a2>@R~BV>T!g z43^BkN<`wtl?9&gT3fPzN0*z_qNg}#yix4vC@vwggHmm@wLoC`rCr98@3GLTI?H`* zq@;*R_yS18cnUaGMxU>7nG+($=e9Q@z?UTWBXD?h$A+7hU#W$_LG zh-_HtS2CoM`Itz3%1hzBl)Zr9GZ!%mt7Dc_iXP604qjG8+pvHhx01gCLu zGXFXTOru^naCble{;@cMCdw(iqOOHD+mg*N`0!vn&1Z;eEE0FAWC@0b?Pn_}y9vxUeS(zHyA6G&0_pVw6fd?+)~rV8iQh;a3*D~qOzh>)WvX8 zu~FqnfJ#d+y(-sMoDygZ#}H$ddZi}@W?{`RLI^@3+K?`ylz+_XECD6V1%-pO?Tv0l z%jY`X+Zi;%4x2o5|L>ne5)?P8pq%GcTKRnM{~iXOO?SPsbQ{Kl{_5VOBfTi?S5IXR zCsIAl9$;q7WtHylN1=_#{x{80=p>`-+&Qr?S${XT|FY%8 zV1Ev#Oz-)ndJqu9!>-(8QUaFvB=2$TBVtN1t{qc5V5dam*}6&Bz%FcM3=S@O&;SgT zbWUO-u^}rKO8dczy`af4jl`x64kotTDCeq;*wgibcD+Ul$yag{V_2c(ok)jW`%6b& z^CMe8)1sU(1z14S>+8iiuX#LXYI+}wl+0wA#!AWuDFL)53ztc^XWulo$uOxPG?$n* z+*2XzWm#1}cyan^sz&XWyG8{xW^I);&W9QCr5CymzMI!ETeVkmteSo&nwT-3$0Qv; zt217GKiePh)HAY>CcW)WfxP+p#-zqbA8E zx~U|uG(lvr33m*o&xt@JNm8tR0!~c7q_y{!?0Rk4=grr%zWct$jY(<@{VJZPcMDhH z;TmkB(1ENJyu`Ed%nKV1jn=70&@eZnx^mTLMuw(+L9ckrt;so3xY6JDB|%}H-i@D! zZ^2Ff>S$p?Fez{D#vVjHxi)~O$^|9v&eW;NEZjy2xd}s!aqCk} z-9R5<%@Rce$ANye_{E`wAM4xe-k)Z*TJqfbxN*^(XuFoGhcW?J#Vu;V9;QgG3{OJ4 zKF5|MYQiW$zS)8uK-^a`1KSV_63R}t6dxr)3^WW)Z=C-7!)Cpo(5)mgwMHy!_7lSH zR_jPoo$ornJg?xkmh#SMV*yLtD?71(58mwDiFBjE`~wG+wJ>GCU)IeMys$5s zW&{Bq#|}N!nWXsQVu>M$8rE@^5O(r)c04=~rD_H3tXX_%*OD6Kfy*bZbp%rTG!_Cx zQ8QLsdWr9Iqu-~m_;U2#W-#KBXVQZmRPAutd7#x~tUwH?l}sQ-J%7^;LN5;IvfWuh z7K8n0l&N{!H~IqY2(@VI2X!?+Or}n|?`KwNz|(-H82gp!<}j!M1=21Sm~M3A+1uI8 z=mk6Bhy1d%V$DA-JMr$+&a~HP-{Mi?%i^9*?XAOE(a2!zLv1402o&t$xhp^p#15z> z(Su0pe^wpsFSD0hrk!gtC0_56d03NKm^Giy>Z@o?`dqOkGpV+$CkdAMP6zR(ylrPU zr?S#E;+zAC0vLsVc-qeF*xFc&KGfGZ$K^BjM0J00O{x4EDH@sZ5iY0HtFAY9`}ite zik3g#skN;uwZoNl%9k;K!Dz%d2?&S~4O%Q#B-&|y5+Xd#in#B;(r0T6drA~fA8hRs zOHN0XOLwzA<48cXkSI3Q9LG4d8s+34ES0-Vr5t$zK<|(7s`<78Y3~&!ZIBuV4o@gb zKW63`k)^XWY~Sv07MzL3mGEF%-tm#f$|H6fG!UyWWjU<)w#ccT%}Ytp6TGwR&K^^pi5@CQ>_HRiBTYNRDw-kPYEJZO+ zLrgx(A!?#zBxJ1y`~Gex+>oCWY6@-|iFOvw=pWJtAmHzIe4Z)mdPXK)6NNdFM$++s zQU^8Qe%tCHSdZZ(pzft&JY=*XZ?Ae?Oz!IiD&!XDUf618srxl-=DI+|B#Wtp!CcTjV8uP^Ckj z^o2g!lnev$RHsLGzv(+l+mAi*d-D!~_|ui%Ow2R{pJm{tBuO4W6xv)O+W@1-w}-@} zvbCZB!dKsvus$Qi?T&IX)5!UBsElIgqykpcfBNu$xddQ~hAvFrB242&9CvPE7(7+L zXy>n^CkK;?H1UMEi}-*+e7Xj4zTRkPT-inEA8LU!#Cq@0k`wA!j6BJpby=?Q|6A%v zu0jWm|At$zZO`)BX3Qn)AGhD^&KcHB#Cb(%-xOn9 zM4Ky@rL?upSyRZn_tC1Md;)=KkC;ApjC>!P`mNA6Oix=n(hNB)V& z$0I}Q@y1v%n@EgzO5{kH23PzNNNjG_U>7n-;?O0eq$^+2lN#sCQ_+rcOQmz86c97p zSAM;7l+dg&NZv|O(~#z2H@fHIMp?@12%kN0dk7}7#EuU?Bg{25tK{E~BbeT7I5i1l z*@DktkwqLqbA`+{k@6;bEZKCByxNjxQGP=7!9jXUkh(K$W~X0sr85%(ekCveNElLOHUAR=Ot^7ldvLY65V7GU=xJOO{>?SvqRkzd5t?Ta+rP@*HV*1aKj$6BvKLyRv$*w&}64v(aaI~|7 z#PQm35*4!cZE zi}_4F;mbCMzZaexlAH-D4D$_^!Nb1>m_Bys4&XReLJeHGrFZn#v0HV#kFz_UD3Sgy z3d#wSJ9oqC{#MT&kBpwY=Xpt$dK)=BA;~%%_To&9wVaZnYwj3`l&sOk#nuenL^O)F zq<-^V_t0Zm*$-J>FnQju>D5j=DP);wW}i55&jhaDK1t}dxY^9b(2hZ(?4b&hMKy8I zzwt%LH6H#fdv1-V%3MXO-uvc%={*)+-V{e$N_AXWk^#RfuqeU@M#CGWO&Bk@jr$;E zPTNJS`23kUs9Y*cLLF?tE3295AY|~w96jHwOeC2-WeQp|LnUXT3fQPOHzh91l785B zWdGi7BZ^@T;Dy)-)d2;aZgFdw9VW4nbd$~wd>KY_IM0gJjp&$2E1~dmsRyzELyK93 z+j0HM5iCv9XmDf}K-^O$J@XJ-5(>M<_d0ga8O6Urc!^(NyH7Z+FBAqKkYa{s}-~DosG$)I8gFOkyz=h$^Hf+ijGeQme@@B!V z@v^XLo1$Cs@-SARj%qkF?YwX%{$7T6%!D1($;pKP@UrRv?wg|KbXGgPrAoTgZv>vu zBne%8wF+Rj*xq{LZzoAV6`S_z=JS%9S4tDs@ zaj5Y8;~pJC&b$A4SlWaMACC;NDKxLp!Ce@z@dr}eTL)Ne8K2}(SSDw}9-{m75I{rq zk@%`OWZA;DV~5A7IG5es`Rj-GMxJ{2({%!+#E;n%cL|(2O1W|1q@T{|^HoKuEhQni z65)VAqSd7!y0!O#)CP<@O$SyVyyNnwj;+ryux7_$3!hEA{eqcJ)%scUS8^_p$3a6= zIj-|RFXcW#HxCI%&;xvBd^R<%wosHWXLS_Ch8Ow6 zU!z84dJYr zYFia%Xyz*YQdgwadCh%hJd!@ym`?pR9C+JyAZdn^tByPhg1BJz%NdI088u@sAe46lpgXV|42R85-9JhrEHENEjg2=dyuBXP2SejZX3aKccS*HD9B0eS0Fpe z=bu|6%34~?EpQc2Y)}r#&;#H=aJ`Q$xdj>wUl3+bx6o5Dr<Dq8;1D89$;#Ca^)c zn|XWKQXB}J8UWeDUDX*6aS04u2AdHV*uYd-$&8geGi5uR3N-`BwV$5CBX z5*8%8e{+8$3b%(`UB#nq=Q3@K+ZG$7b`xOj!B@=6HpgGMB(lqf!(Ub42lEBQ#!on( z?sd{W;Hk=pU(9hFSkhtbRw zs4&_D%Z4T?=BvQa2E7>>3MMSr@+k>o;2u|s zn;(t<1R6m8!W78K4lELFaxHIvD#b8c%G&fbX&9B?Ox751?-hjUEB8GCLUsXjUxsB_ zmt#6;5w_eL{~ebhO4z~UE}F8(wg1D2Mqp||28Ay%Sm9F8R-5JiFwcOzX_7GczVVx1 zGO!HRl|SSyWZQUx@a9vU^9g_4Ik}i?N&6$<}(PAkEgTS%0+sBG&rMGw! z%XK(w{P`Z!$CmKxN@GyI3Vm-V-mrT#}?pyW`Ud+{eKO%L7KrYk;1}T+pB)M`me(@8Y zK{}UH>~%z@w8z5fL#)c`sVU{&K@+7d+=oh|v&A%r#b5y$S+!TVz8Z;^-S4{sdh71m zQV2t8jR8V?qkm+wfoUVn(d07`&D&fYO++ar^7p`=OkY>t7J~pl+@$yEXd8xwfwLl` z+`A!K#f54$&{MXArV-+k(OiyF@J?-fZ`qge!=zl`BX~v3(|RowaDQSat3Ip@qy|opkzxw zM!#BLA5}=5Q<7WKcxe@XReC?1%*ZMyKtBP`e}av3=a2<@Ag{LS2fu(Z=nIH zVdF!7O?nQ8uncAmHuWW#DtbJ-y@Y+&1I(w5n|YpjPn;%en=er#yn;!dEBEN33D1Af zwTJU>dOrdx>^Idx*D5@xjWk>PqP=|O^(u_NDCiaym+GyP9TvfcGCzNzgr)@^ov^N4 z83;6U-DRJ}YT7k^+Uid^lL+ur!;xL^E~2E5o%QNGk;HzLYWE!A%v&;l!(bOA%{N}J z;#SN-M~-1<)GMd(qqGjt;xoKkB6A9QvtF;Z^!_BHC9SxAXN(fop~i#`4WWWe#E}9; zU-agAN8kCb_F(h}69hj)4v!Z3EGe-RJ~q3_lUcREIH0Oq?SJ$^ec6=IJuU5QYsj(O znlB_j4XG2%vbhtinM||J10BX^ZT!Q*FhyWi;wpdv5(GST1QfiPJg$+VB{ZMUw;?y-WBq5lFDo#C}h~U^o{lgg3yx@qo7g z5brzx5-@M2YD`qo`yU0}encQ{J3c*@ZTHW)VQ)AfW%5voe9RLrz9up`;|AOk=JOMsIU^Or%#% z+3kg6^?fNB$sbu{tbX~2%V8`-Y(52GkFA^;{?3lzXHq_pI@3wi?nj$c#FoRn3Iu`s z{Vi=N)~gtEb+2vjX+%}iy5wK_d&&Q$)4D1iZ;&nQ9nWCdr@wk2FlsX;OhBf?l~P;z zFVM$Tye47@nznjWEk5NQeAbKK=f}X;A?q)9&>%l_UZMiPEB1&0kJY%A&G3f{wjwzd zsC7~w)+M{Wc*KTGU{x-`Ef;P{VumT4d4t5Y0nFfRaQNj1j9&@Ya1DOm=U`E&J8#&d zqIA2B;xAwX7ZNFzq}c*<8Y2}@TlvW^;`mGc>UU>CewYc4Ni$mJ@?AvG)LapK7fjLT zTg}Js_n|*6>Q4}H(+#<_Gdn?TcpVUFu~OSrWd~gL8QtkizLCLtV|-Yi#=`!#ObN9L zvaUWvU}TP=LIFZiV6yd{v~cTjN*#<{i$?WSJuC6TkrV9Lq~%;SF&Xv7ltzaOMTak1pRp$#9Jc#R!;vc znG++NO1+G{`BT|4GK~cnK~yqLO69(WtZg>!{cZO2!>lP;ok1~TCXzL9Mo#(fVWx9w zOQ-hfO`v!Zvq5?*for;ZKFL{sn!|n~z}wl`wv^%;hj2L z{a5Gb7CTEfNQwMgi`~8zT!17nufUB4G+%2(!~1hbgC&%JnK&Ogz@&3s)XTEf=S2|Qd=^EfNk?BNn#(0Ddt?UVXW~kw#sy^bA)im zz5#tk$=t9+`trfZJO)>D+@rdh4V}tkailSiE9nngOG2U@CEMkKTMZ4WD{tP0vWcFm zoTLP$!av#GOkVL*u|L&sPiGbjMyBy7yx()!q(qKb#Wej%uqEh}f`H#DjQ!@puhO z*YRE}i@_v0_O8wZb1~VkDXQ&?^-&LbBLf+WF4ojiKA4H28lM0SOc+eVq_-x-ZDKyp zXA@AbWvxN_T8sHW@L_Ig4Az5G!DngVz}Fl0WhE0T-zuCO2^13`2D|`$1I4#=%gT14 zmv7n-AIB47BPiaD zlf<~T8YulGL`jsSg-Hz zeS~J0)!FbbOdL1-g%h$>{|`to1E6VFnPFr9GHlf}l`!;|AN~?G+cII16X~caobOwx zh|Ou_yYE@ZHHlv;?~Q{bq~0S%L~CRLYw^xND|<=i=!+%9A%`ZqqRQ=it2gacpRCh# z3&e1oO*+3mg#G3VCY=ZWJvU0$Pb~j0Rh=0$e;3P`LN8 zJ zpEq;4hm;#DJRYQf?R)+#5#R~QB*$;?unc5ipTF_k2sIUY28a%pm3ZPQyt5`XV-A@17s3ahK$=2B{(2v0!~rQt66 zL$&eoxXQ1c(W+FtdVxt7!P*YZ%W2qiyr&`r>yodr9F2Y(0iSn9svj_!YXuUuVkP&1 z@<{$)BZ99-N&q(hS-#3XnY`I{SRSuT!2#f2!M%v@cpyq_s5cwKHAGu^Twpgy6AYpg zJNnSnpRHMB26vvx(hxz8H^DFS6JAF=rOb5eQO&IwF@Ga)DW4Z)*NwYZ!gW4sf5&u$ zQ6Wrsq%n=6!0j5CO$s=nq3bf~V%zd8Cs?#puFaHiMbGc>qGK(D5C0En-5Ue;kf&*w zAY845+UzboQnO`3zyACz6F;+6=(i3z6I42npOj|w&QRmeD~O&CJ8cTPxDSj=^>`En z*VuK?4iZUnQBV1+h*Gba)-IP1pF6YLLncGPS$8TV;q1iEdUCh34sE{*W1U9=tpd7D@tLMNP~q{YXbY-)+N`M+1?Tzz>U*o zZB=0;?P`Dg#?ic0!N`^K{ajyZBGg5!dR}hfvn)|;_fF$VHcEoqmroagNS{!@&Nna!)wQd2Y6b*w?hHDya2Bj=7ZXul| zzQN-1_~Rq=bY+~+i4Wps1Cd2D_f~^j;@>*ik}7~Hzuj|v`BKef%0wcH)te;%5s0~U zN`e;!YO1+5GFJZBo@c0ryn%l$6`#nRSPa7Kz-}E^B$o3_D5P1W)96U#HB=_}E{K^X znS^)xQZWOuvc`e-G3&#jk19czYiyGE;WZsbR5%`~6fxUhDwRH(!50gCO;<#CT{GR8 z{*-$hVJ0Tf-FDUb2m1oW`CN5ULJKf_x!Uo#COE8jWp7oY1jK(~Tbw77V!=lA&FI+&yNDRw8W^6B9w3GpECbf#+YS&xnfa{}8iQ$sJR=cHL zo*U|;^(_i}C{2N=U-tU+=pl*T zW}Nd4h62&-G81$6W(W{;q(g(xW2Q+j76eusj^1*_k=V3&DE{N6li-p5w^)2^|Dss1 zgFhdaffo-y%ot8$(T<5TGd<#~F8c3UTB%p}3Ga{EL@8nli1qretIB~5s77T6yg}nl z`7v9+)FQ9G;e2yILl{y#EMGO7%v4mS&5aWa{dDzT z&<@fauE8OY2eBdLjZ`&11Ju8bbB`Tzsk>y`=#YfRcf|G+UpivQe4 z_EMExCEYUT^);jzfk!n80f|95n|GkF3tA|JkQ`|=C-TQ zL6yJ{t#O1h+pF zwxzXBD65`}XOrEu=O=N6IX=uc*tm4zx~ZhZ+^JJ?=L5u>(Hf!xIqDd;)tO&dTaYBX zpNTft$u3(Hx}jN%IpPn$>^@%RFwVs4ViEzHBB7KZF~yEyF~{o;fq>pKm9<{YQwY^+ z>sX1j&Z#Kf|C0M}@|#|*q0zpUNX2NlC(=C?*IxLM!G~$c3V5 z-9a?p5XKB}xDqZwMP&&Xt4ceT z1#%$Hm(eVkE00KU^_Xx{u4ZUV5CCK4K!_kW0B@t0VxiWPh)vR`P4$dw4k3DW-`BbY zI>kdTnG8>hva7yeEr>uYjDHOP!UQjMP?dLMW>xg7Gd$%E^p1a&8hvU*Db%b`suB!d z4*M%c7^t6AF|uFeDf_4Flz(pBtW7Wf@@1%Wbl|7DU{Ki&efI!(m8BQNpGcXI&fEj9La{#{X{tro2T*6fg?7`;oYi z(wrQ=yMth%vv#66Yi&9jqc?+FQv4aYVS?JToe-novd6F6$T`TZaST&cL|DuWXwX_l z0Q#Nj$}wfThxwO2?xL*=s0_%JvYc_0O`Rkl?2=M%DQS(KaKfCwMm4=cCZT6eeVY=L zR!`|7r}tN|Q2VgD^$M7wJb)~vXC^w|!>`?Xp{WVBHE{>Tqo|m8-Ahkx%%TsodaO$F=Xx}o4sa{{C$c^?=UB@bXS4@`Z@Az}fO6$A z4a@Q~cTQcUFxZQF@bA7;H%|Dj&r2p)F?yXEBDh)jT0f2dNi>x4NMI?r_mn2GdP0n# z6{gIms2HZfM>IPOs3g8{`;DY@uPbo4*V_Xq+U0DaGa)(HKO^nSE&Hs*L1c88vp^oC z^Ta>>Ml{!bC=VtGHwC#*6DYEbMUCC36n%d1&ZIkSH4rB6^A4b~Qgzt>p8*^Fi#Iov zY5^{xOG-1E)C)rXeC}(xbXB$HbBKeB&NDcMd_Q!JW z3s)+sS4zJuAigyOZI2n;KT-m3v9EwGFv&DWX!S{Jo4#bfr`=D%u3%i}@x!~`gLh1L z;^ChV3u1HHLC#!p_PV&2{T*PJoMh9ph5tAvVdPC8z2nU2lrOkhrSmkv^$X}|G4rvl zD=Pepv|CnkVA*|C7J1I1EuZrZB(|X4-Sx{7=VNkcHz#vV!59&}E_Zu<)xEh2(k5i2 ze+yQTass@N!o|eA3u0j+u^?vMo0^xOnm)Zhapk%X!AF@#XMHBnRm@M`@OrYI= z^7-V_{mCg9gWMW}N2=qo{AOWY*%|$PG$?&U4&{gJQ}MFvm@B{k+Txn|FF~ua$%_Hi zWHQ2x4l|LQ(SN?#fCuVtivi(h=xApec>ajU*^7z?8BifcqHq8B4M-B0*8&jVXr%L|^)M8WFVkXRhO6Ho?Qkv$e47f`K9z#yV@lvjT8$N%~H~L#TbyssO%kIja0$ z$_2D*f+wVDJ>Jqk=&m5nwond+JM`D=HZ7H@PRS;kMH9UXX0Xw>Xc30oDLoBxzQIBR zjMvzIw@@4OBqn-JD0;Fj#6kcBM=SCE^2 z1DU?XDU+XTs80|D0(aUxki)G0qn$!Fw_+VuTS;e$ouRo9j07lE+Y+)Bjz_G6X0A{r zdh%`F;M&4?qia_gSHRZ&-h=rs*J*-@7-y8^6a`t+Z*H?bX6ajVF=U5EEoL2th9{hc z@2e)eRN2%M26#gjmRf*ks?7Tvk7aSGmX?PN18dXrkz$|N{@zJ=ZV4qvl^Mev-Q4{D z-rSS1uXE2T3EZC2EG`yq&81>+$H@YUYPn|Er8}o&T=@elRa8~Y`n1vHv*@6$yUzYJEQnajZfnJje_r}YRD-mVM98!; zoM~-(fG#(`q{3omlPvgNW>XfZNFHp9;@eAR>{H3qMa~e-Cg4oIrSY56P=H-Z0&v$- zq8}Cl&hoa0zyZQUH|lD`SV*@v;`Tj^&n-<42h~K%`?5{gWNysOyZUH;M>=l_qqM{S zyL}p61$#dR)JXcD0Fkt9gCyHgs9kCkpH`_6!aL9jDb|@Yeq8fZt?J$-`5&T zzhETc9}FA+ch3EjYd0^ZUn*(e$)WpXpr7V7pso>=CO+ z_P)T4ydg`Z6FR23a*eVA#c*T|0)n-^MNq%z6OYyDk&r6c#W zw8$ZPpo@nz3cK=lh0wf>n1z2Kh0Qm7cR7SHF*M%}s8;V*dsR=;olD`qTWeV*eR zv!r2yC{kj?o|V5-1jC=j3{Re5ys%#2c|i&LLPXeGNkbvCxjQkYUw};Sh_U|4!w!g2IO&;C}Zh~+cQh}o014Hpv zI+>_~Ix57$2>pXHAkAq%0GC$=zh6m%Z)djvh;?vy{Vg9C@Ma|{)F%Xf9P_Cw*<~0r zA1c_v@TIrO#x@zzKA#F43oj(L&QTB#%>bW3xuuWE!dPn%)U!PC51cQ>&+H!sDO zSzjS0LAhOd+RzG-S8)Dv>mPHpjShm6NHR$$2OSbRb3sNUk~(DX@vP@R_mW68RJoF5 z)F;x34y+!D9Ttn>{3v;S6Wf?4DS72p%%ijQ!) z*&)!DM}jW-ugBoQcQ=dd(G--j${^^~-9oMjcEQKO9Zf+@__IV!jy~?6g|fXsW=KO~ zPq?D3vf!N3uZs>jcINo4?6CA(mc7i_A`+b=b|Cg;r!=3>320xG9+bF(U5;u6e@z4M zIwE>k;IHK=181lu-(T8^__-2LBbdc^C!5Ag))5HAYVb#tka>z@VIp=Bpc$!9F>ph@ zsG~Lb29^rT@8dLq3>ahp_|P_A1J=74;Ba|Q5>p?)T?TZwEzd&tSrI7C`sHa>p!Tyw zPd)!{G^?IGo)IAWfV$VA27h30!j(ylwqUM8L?^!sK%N=Bo67FTy5 z+CPWCG)-Em(k?nPK;uTKC!QL8cu>kgaw`Tw0j>AbKki?$98AIx#wX9#)8()>XO?Z( zC1JzrI1zWT-nc=+yTOH0|0sZUg$w~*FY>)>V}!C#!oU9MECnj-Fenuyvgr@?3IPTP z;gf%^YhMhK<+l9IS85E4347$68As$Ag)CA4lidXi{pX$^WUQRB_Wwevqy>P4yKCBu zTEkD|P7N8)4Ji7WG9F_XWXh)t&byHgE2^@E2pK%tvFx8^SF+4$Ik9)hGi$4~(FnDC zUyrA0VKaEE+JR1V|DZwli-M1M(r+TZY+-cleWHT9(*G+8yjN@c)*N+D5*gde;)IS2 z_q{|yCq)5(or~vsc!g;8RMvg;ZKy7_xtoZwjqh4rwwC~_-}|1){P>O6uE1oZhCc0V z5MO2eHUsUdRwjAZVBN3;X1t+BZL@12y4z4nRHC!{wT34kCh>|MPz88Lxq_RQD{99Fh+_H@6?l+!jk0=^>C{}VnsE5lc)S)6TLR%o_0B*=6PWiBCcoz4#nT8s3F#t3 z`F0GTj!!fRKegejcl4q_H?%JiF>~2%c)@N4;wokA^VPs3%~9HHn4&tDiE~UICNW3$ zT0%I6V>$!-ivNs#F0)o3q^boNr_xdwe*DG)k^o+p*Yv^S7m`%KR7*99(}IA}qQxyf zihv^(#sz>B%8duMi~9CV)`)vUde5xzsPO-<%;g+Y{5alc6s5mMwF&`yETUoYU!$B5 z0!L(f?%;dGyP&}E=M2mrTc8;<|6sruZi+>hDr>)hsZVb5z=;4zRnOs&C3Y1BB0(9Y z_ro97kcXC4b5*~Sf4G*#<<=0qQfC@v&D7GCJwe(}4^_WiFlNAHGESVyun9;!h-rO( z)NVXw8`G5C)tDY+NYWgl3;aQT$UpzQ+RnKiK*n{mazC`vRW(i%*rcd5Q!}PYg=ic$ zksDq#-43Tzmu8-x^$L}O>2Z)3=w1CTZ`<1#-z8d`$WplD3LwvfVNHqlc-cD7-ZU#A zrRoT46E0iGfzGjJQjtXjyW$>$Ztx*0_mk21Oh}tSbvvm&+}t9GBvbd>33zlw_}Y+= zZc@Ek6%a_h9>E<=Vl;WW`H?zo#2C`mb`f-d>;6ZJflzs8i|bFFSf6*!*c&n8g?ClC zS^$$;mn8GQ;U?{9HCA{0zW$+4?GsH_%+9j10cinOk;zJWS7cn+3;xsETQ0(W$^puX z;Y$(5cj>M6Kl(qJ`k;1a_+sin1fwg8pwZ=%l%II;^fkE8*+!`0FV*i&kekLSpA)g{ z!R*0UL>@VUw#lz!-iuL`3|Z{=s3RN#UFLzW3OW2Q|ZUtQjbn7AQqBTFsLHz*`C&WS1g~cfEOXg;lrRhxtJCX*se0*$o zcWJ6RanRzpJPWa^cvDK*A^>SI8?(B)Q9Tg_9pSMa3TBLvH4;Ir?VX*RE8vAw=k-$~Z*q+ggD~y>p z#!iBUt4=AI(Fp5`>=O>XVB%^vjwyIIB5erm8Y6D;a}i2csl58S>YN*fmIC6|c1 z{`aSD+!Q^o%n)@!>`UBjZ_roU>83d1Y&B6wDs*PBfgsCQg697JnPk7J)e34uQ{AYm zwJ){2#IS*9iYU6jDfg4>N_33-45UJS!r~r^vhRj|?DeM7Yjf;Sp|W)Kd+Xcg+jNzd z;12SDA>?wMTI*j)9H~Aj^jZv#fYV`h{PM5k7Vux6rS;PL5rQq&^cd=bo_5N$tf@@t zd1o=f-^cKhLe=f~x@V*;IrwMTJa8q6If=u5fK%aB<#(2BqZ3wID+0oZxzI7JbGb*V zzck0q{ZdGtk|m`AqClV~rOo0!0YSP*l1SM)&t}wrZ~=V^-+u_ zsf_j!po9cB$3VXg_|~>#lhDF0+^%Az838%LPrAegzOa`Pw05AZA6Y8O%m2bZx{~KQ z(Eh|W*j9B-`XRjPa27*+OgZ`Kmb7nQ#%UxnIX4%gUxK5Imj?)!)8~gu7dMW!KDB7< zUrlvh#aRXU()-}{;V%TB7yEC)p!)y{Vz_~#aqx^KflDMnx*-o#oC1rB-Z}+Wem&H) z2OJvSZbU0Z%vj2?%tas;jatO0-eQ*gHqc-f10Neby4Noits`ztm0&bMP^_p-*bidR zj=fR9>@!f`Y1tb6x;o@Y5E`DhVG_V62=#R+r+BzR>v<||>4|AapVe(@rzu7?7mlMz zWa(xcr@f7`VRS+HR?2pzli>S&A{To`!U$w=lTffz!*>~$#B)z8E25D~zT%3}$^jW13`KP4}|CBGne{rJvqHy0Sb_F~_ zEA*n2#{QsjO^Upt5M4FWYAbWS$PF&v%R_sg6#mh91!qtxcK9ydmo5x7ZQ88CH5Sk% zmkO)ti*pss=CJ1Nfe7dhOH(pNPHAW0#VhnkQwSDW67(V2S!M&7URk()QyH(07FiyzYj; z0fMqNPJIP-cGt)qxgn<;9@ zWUPt3rvB_XS$GVga$v7HMgCJ z!GZBv5&L>VD!~M4A18NoTY~}vJvMi$`k@P9e@8+Vn9X`Df(Bu{TeEg!@Kj|&lm7pG z(9sP9Oi`TKEY=pVh@hJ<_Z~k4{K~Z;xX2s>+Na>YpG5#QM^lM{Zmkp0yg1AYwbrMH zNCG`C!=_{Swf$QR*s`s2*U_9|3E8X=u}3^>GHd~DfEjNZd~vjduwSs+q9s{09~VtR zY6|&FE=kd{WPa}+EDfF~G7AMb7fpwTy%dMxqy9n{t4*jbL7|bmgNwK}0XJPi@EN0e z=%4@PP8(WKEA1%A$oM<>p^Z9P#x}OGr{nz#1&V21OGm+QaedmF-1M_T)p?DwdS;$o z>OvYC+ETA@l#V4%yKzrGM@AC>>fPR~oo=v^;O#A_d+%)vP zmXJva@t!my%IIU&0?BT|10Ypl`&mO4S~n<_g0qCe{lZhO5m|x>24rV(o}=a9FXp1G zMs$0ys>7gi7SRo&$6ZOjiMX~@OQ{xQX1hJx^%P+`d{gb+Ne5Ay z)=oB?-T(YG+lH2PSPd@uX;e=yd>y_0vr&tg#A*DDh3O)nPJvxoYjD#00x#PJ^h&*j z97m+foXKECEY85R@qbw*LLcISsIovw)RsBy!%2JpHWs7~OC(r6>;mI8l#z5kF`O=!yOF#gK zYG|YGk3PMr#WDx+!>( zHFKDms5uGt=1%>i*(^yVBForxxFs~8H>|fQG9G6$fE0*d&Y-O51?c6(JZI_0P@JgM zr$?VG>sCh5;wzU4_dhBQtyf;ongt8YruJAyAvLQL0sJXpEAa(Z%!%V5- zws#XdNe6uakOlpGztA%&PRsiVi9L~-N3J>P4YgCyrX72gas4sJ%%6#gbOFsAub=D% z(7N4#z4w3=IA%CUtAz3pH+Osh;g?I_5EnBg3+D-6$Ozt;&K%bEj!Y4>jJUj*C zh~0UJW*#P3y&X|Dn$P~5+-bG99jvpXqp~UeY=(<{$SE$FYVbZdE570)rkyIhGCe=` z+L2#u6uMUHcNxk0LH8X&gX05Zp}_ci+7dI+`y3w1LX z1eUE^IN3T_!Uoa{hCmPozoTk8Qi(U8J-2ZpBi{Y6#F{FF?U`*Bf$TUrtEKAIthUlq z?G`7?g`J`TY@f`cgtQfQ2qB#n<*^wd7@u8Fm4~**JCWqcp7^4J0TZ9?g z4mxI<{E|`t;e)~d`uijHMq~^pm*hP-0tLg`R5>NVPw2;8&=u@asz$B=j)^lJmarqT1IZ!E%n8J;g8(M1i>Zw&#pXLoF z>=`wcQGe?5Uh7hA!Wz?O=={^TP5>twTnaGwzSOzbm~r{7T1s&}-IdpmQ37vH;ed%r z=17zdEF{ZYflz`rAVw*6d-4W#k`qfXiTVhMDu1w{N#v1~X>nGNLwdmh9|}ERT4k;2 zk->s)Z}MM}BW_OY1>as`7d1bWpcXs5Grin1Zmhv+50KKo&FjRlG%=w8-sl+@N;iMN zQO?ux=FBo2+deHZ@g(L^<6ru)@_Q3Zdw^B`picVX%z=XjoB$Zx#Ru1^s+9qWE_WFp zE;M8CMzg6nNuDcCT>XR|YL>(pV(sh<0Ape92_-=MJ6N4sV23t9 zwu5}z9xsgrtp(T&B580U>o#RE5JNWGc-Tr;X1@iTY{nSp`tiOSv|XxU`PD}3s+I!> zF<+{4^Z~x@WUte-5Xfh~-ofjP04nX2fKgLP_214<`{LD^bT^N+DJL>rI{Sv|!Q1}6B(`X|7^wn#ujnJ~ThohV>j1ERb4I9HXu zq!ntPM0;so#c*Qw>FV9YEm4n3D;B;OB)lrU;{lEOJ}5i z*&-lp+(uJY&-%q4!Inpqqf5}gaSKgV!iq1eQ0LdtAY+EM)dzg_vsy^2d-e;qX|C~s zR^gMui)>&PV9vvGY*w5MSlzD8QB&RZusG}Z0O`I9lhi7sGWa++)6BqY8R=16O&m^| zfxza-^Wf&}L(SKj5PGyJyfHTnF3k2VGf-`2K-5!~4Q6DsC3UN?X<=Sy8fBb{RmK5jtsnPOD zztr}^7%}zv7RU6d3|U+r~1AiKuxXwWnD$SVkD zv(iJ0SIgWP?J#A3K*!)8fw*HABbp1m{{$=Zt}h;2Ndy8{Yro{XqhH|!`d+l6X}G09 zrZV%WCYZkaTK6#4KCzS;`9XYRACMD-PorxEaI#q?>-f+|^{%DD zpabb}Si_tpA@PrIi4o(g9hWdtQ4AV&w}+O`+cMk%4g_yq*sig>m#9C1ptPRPl53Tn z5EA(XU6L_n@xg~L(5+~TcQ{lh5L?7@hhm3YjLc(eU!8HG_4WI&tyS4FXo)W(6$US) z338^ojI>A+1~EsUfk|NMrR0hO$c6fh*S6rXI;Nlw2483h1?jjNlrDXS@&t!6ca-(c z`bvx-coDYXpqjP%o;xjO%e!Yb^0G;CU<&F?DIo(k{p|%Xn$A1C0 zH!ATxRK--#n^&L(PSZ6Nq{1T3ixUDmG_4fH=4I-q1g3VC7SAHvSO6(r4ckFUb83b! z#+caBj*Lw6k^cDrH$ce0)AV)!V19Niyf(pr?s6{2pS9=33IBnjMi0mdpJO(q2wc1B zPQkv_?`)!k+1<^W@ar3XrwPFbV~Y_5zGrTRNO!dhDKlIm(bMK%Rh`@O zQQw0dv=M~!wG$D=d?HFF%98k~MKf`D+2>Fe4VA`&1%LnRY4rT-YU917jQ;utX!4pb zDemlw^bmbz7YFDgR`>NZu?(qm1gUDp^U0!Kc(un5ghEev3pw9kSCk#?xM`n_!#gy@ zQ7__`(Sq2mF_D}QyKMZ}CQ8EO3PE1a4HhN&oq1#`}CD$ZBCrcpAvg9@Yn^n{ECxkNb+~b9x zA?Q>-7y_kqQNyVpThskxUO~$vhG*pw zKfV(?1}~@wb|S2@YRDFIV9(N0TW=vCvvm7vIj-3SX>E$-({cJCea5r-wWqJ36<9B) zi}_V9N;$2(6bAYJ;}=4wV=fVBSd+jL9}^yMb?O2kghh|1E~l6GVnq~Lq5T+JX&zUZ z?reo8`=h&ZTLbJHb5~4xA|sDNJuuvcE0e1lXt9<4*cg*_R@xGu!Q$%22MjKnW`I^@DF)yB+w5HCRJB-F!!QXKt<@qECsw-WW#*0$ov)o0 zmVqI&77PtU``;BmdAeG)j}IIrd1O~m2ZWod-kD`DWgiI?^Vo(Cfkb z?237ds;pM*L1LU=SroJ7zHxrZnkwR)E<37f6h7XuY#qpml5bZdCXf4^_-!ZlIRt~N zSS6a)=aM9hvs8B5kof0M-q{^9QxgaHDkUrQjLnN3UP6fsA4WYxD0INS?N-VG%w%jw zM&W4d5)#m@p(3NGzWYn{8Bmp!LyZu(oC-0wm|@HvP~9VkgNXqh z7`e86PM1F8hsFUibXdt1q&;$?oi!E9MTq%w;^7wUN+*800#px9;{PK{FW;?!6aG-$D7%%dZ6 z4BY-6;|9Y8qC9%~G#daXZ+hTNjXd4P!AoW8d%sZqc)VeYqEh9_)N|x;xH&2g`Q$DC zfE~FTk!9gi&~eZLni21NwcLBrLwt4o5gmAO@s{d)nG|-Cs==L`Zc-qBR5Fn(v=|D? zd^O{;Vy4wiJG_?sT#bm_TOo|LhmA?23s>R(D7-*pz@HRj8cZ!0*-OUT{d0l%aK$ZI z3Iku^cJvrh* zEYPB9Yts@D8nULzVFX%Q6C8d}o~n8s;7i?dQstAAacW0+atc|#WH)VXL8{g#2u5>K z%h~v0a@ak}TWL>UeRhXt^ql*g5dp;oXS1tCN85RtNXvHl^0)MA*mV-9$XlHPpPFhH zoK|C1jI%aj)9^w@FYX*y<5kAzK}#&-S5Mb{ugAS`c)SmdnP}5sG})VD&+2{lG(P76 z1NwL_*Vw6cyvb6gP4Sh3J6pHa)tI{-+kqYxs7Wpk+JHj)AN_l;P}lq2g$$SipPY9q zPWgX7rI!m=|4P~H19Caka+=Rz1gzPFDk|yZVm#;^s_58N+yiORq=zt}*HiHc$`;y1 zkC(Uk56@a%0}i6<);ScmYBcr^EJ)XVHwK~ffmI6Mqbmfk{w5HA3a=HSTtKO zgG4!>5fL_a!U3FN(Y6LP-dm^l+K2pPy7BfGT8NYMhQ9i6{?r*~yOz^%GZaiOB-xlA zA-Jxfxf{Kz1D%WMR_D8#?w65a*Wo}Cc9XCDZV}8I?2BDrY$kl4_`!}3X;4!oc<3bs z5}*U^Qax6Hzjd+!HD@ZTO>`szS<;KqcS1LAs02uu^2@2g_?B}%BovoxQh8{Thu?zD_3IPaq+4Fm<>7K6B6_1hD+Z3E#X@Pfyik=r{AX@O`y*wbx&^4#k2RVY7Rcsny zTlg=FJRl(R6%9+=szNkNcQDL6IiD9DxXM*?)Tl#w2dSIB0f;go(NNu(kl?-Kn_cto zJX0aPMSk+$E~MJg^^78A473fYv8l1Er)41$j@8DBr4C|Nd>5HP5-jUSf!S^ z^4OHTqzAvJ#odlBlTxS5JVPoDq}A>3iVG5pf_X01&CH@O5eIhkEUt626znI%b*c^8 zs{{4pmu>u&qgGIjyu1B1o0=WDHN$a!0HS|WjGjOSD6hX|+u+!Guxg)f)&Eigx{2yf zm)DjVqv0}Fi^UOnMB^8&GQZ=GyW#xcAF=dhLYZbrZ2yZ+AZ-r)e+cZQg_2I0e-{n! zk+!m+dN@CmNKlIx7#-;=Bl_e>uTs>+&Ilo5+U#6(A}f?&fhyurcONPs_A{*5K>~I+KN06wwC4gYjcB_F63zp$m1CI(Vx*k?U_p3LE?qAr1|UQOXm*DwffK-cMTmD zXrrXc5EoIDLQrYyIAtmQhJqL%RwgJ&G7%CwG=?K>-$GQbPio`@F=*O4MkyAr095e| z?vTDJJ`7}18UP+>^$?ELg7k^N@Rpcew7+?H{u%~NIC5vfIgC>&x4cwGO2%GJMWO>f zV-w1l{ogAgfThRnzi|`ume#s(p04i2DqbMF{4W)aX3{;#Dbfwtm276eYtiuT{Wyk4)Nla64$L%&n>y`-QE$Be@T zK79yvIE&f8MSTzh5~c!Ne2wM#q6XJei-~YnYg$$0ZI|wFc`N|lnjVsJx3G69uL6cy z^k2p$jkXP3*KNclSan05Jq*_{9eYS?%TA)m%{vsifhmM#n=r`)GtQv(VBZtMv|20X z68KYc=-07Ir_6rQ>Dd)CiQD2@B8`9%XM_la_0o8@9L+A*u8j(D?4OuKKuIgog^ZWk zlrayH^GeT|+PIaBMtQFWZcheid0=0QQt4zJ^|M|{k2Q=20^f+POgX9gxs1Igk{<4c zSxMb9T2NBBj)D;NU8p^rk@^E$dJ9kxmDjnOhLAj5maFy&o~{is>fs#os!`NiaJ>Tz zzQlOM6<~LRlRE4CKmUOoi**3k{bzH4$Ro$XkXxR{vhh?eo#go~j;U;4`awL_4As#4 z2B4II4CtEY4U-1>Y0Kg8n;pO;)HY6{KfR&#L2yDwpr}<$2@ItFe5R*o$rG=b{r3Hi zbXrhtKK83_S_1dZoSxWd^oY*YIHj5XiEz3LaKK^Hu}U1I!FpsPFnaYP0&B*n*F$TW znZjr~(Y@{;rqvh?M8L`D_UUkhF_}rK%{!*%*F$yvM0=bil9?1_RN-EXU`K%X#kWtr zx|y99z3(zRNTuZks(|8defaucTS9Oy3ye&EdwwVIK+S>pnj))ZI9 zEc$MRisBzFQ{ELN-{}85!efwB$_VcNR5HJT{NQDPJ{Nd*?`zu?xqXO#EfAt>5rkscKMR6*3(Dvc)fd*s1Cg|8 z;F+E?-n9SccNNipV<&$v25O$yn!PSkz?IAqb+h`DMh&2T1|wSNX+wK`O|ulW<{Yp5 z`}1vT?K&1_;&xY(tcy5SBU#rI#WDaYpA*C@Wz5N)@9bspK($CXSG8=L@_BkNuIwTD zB=_n>mPa~>()eJ0nBD2Q{ZrJDU(&8Nt8ngpSF0M?oo|fZC?Tk1OD~q@eYjpWETkly z-6&pboESPCgRnG$lhy9M&<3*OBn8wXfJ*!gB`v7F5JV;zWqyMyXUnKnK2xSs_vdJz z|GylODcGaXvTqhI0_lA2J}Kwf3Yb3~?HA0)@CShgvM>S<;w??yi`EWnM(0IOHKH9e zUJaVj$fWZ^JD7HW99QL>Tk5V!KYrj@oXMTis^;y4BpFztqN>Uvs0AW5xlb`R;)?YJ zVPV4hHPVtHOTC2LS%V~%QDVi8wAwavt_q0|oQA*w^~&UMg-*i`0OyzG9EA@%0ktIG zL7#lVm=Q=Qz&$xK!p515ONOg2Y9|Pz{Le;em4zU?x-0tWbjs`mf~tkrNh(csqj*d^p`M9;Wc z7sB>-X=oGaVi1y*fQj4}BamDAj3R>ve9}HHq8;$}cV`Sy zir{qA0cxH@YncEBQg;M6%SqobZrKNFQK__DTKf!!>0efvljrvo+2fCdGggXtrSX$2 zRpump{XZmA*=2;Xy9Wru=d01xCP=wiw!Rg{apA3D_k`H24Omh2PGI&UA2vL-Y5(L( zq?yk{WelQdS2d0K_0cgTZGTt0)hbDyRqZ1W$<*ve=!j7s*j_rMT%I(*p8v7`Niqk0 z!`xLKzJu4U^-x5fPOvi)D}tPxoD)VOU=aDt46WX1>+rr}(IJMTlst=N#=`q*JmHV@ zpHRbG&;YI-439JwCRZnP*6uR@5(F*A`|cWqAz;ORqO)+Gqkyok(87P;yB2b5e6#Nm zq6MJQGzGAO5m66PP=mzWb1T4()AT;*osfo|p_ByI;Ekaz6c$=fQRzCqjY#Sg|3c0z za$TA{8-wse+|4xG#DS;)86i48vN}Lmllm#)s+%(-fvNlTtXsYJGc|Hku&_ASFnkw~nA=mc@c@NT&R4_+f8+iRJRMq9O z#2GmJ^)X<`EV^_M=_k?VMj8`@Dp~2vxk85016%KTNuSbm9g7-K)eiWzp?dlkwrSX_f4p zNi8*a3Ub&YO1oU0)+_%cnyl8Mt5m0MKtpHiH$i3oo1xI;)x{s?P#{gQM*A^;g2`=c zFMdr+f`tsz3YkIh{oEzu`?r3F(4HNp_wwnhsjXxUNJLZ~Zf`cs{v5RyvwyzD>#@vgg0cNgjdfiHRzZS&sCL?pjbFD;lUb$RxNnE>zL2X)UR79*MQ;Jj{hB46h0 z&!i@Ou$?JOgtk4gTF=(3|DLOUCcN4mTXR`eCbVkO(7U-i;qLv=Q44GB9;ddkexRv> z;-&2)L~{G2LWm%ab4~q_%CpzLO#yQC-T*gJ*!8J(j6ZYuvn{oue_!-G5vu99K#K_- z!gGAd4#tQKwkK1@PXO7}YskmsTTx#;uX=8U*vhc}MAm*0y?wdI*k!=Ap}t!jFcWR0 zZ;`ZR4LwN@+#79{Dl7EDS++gu>h zF`O5G=BCOD&mp}1@5vCOoJZ%pJv5<~3r*V68zf|@s>{MZrZk`W4hWbTM#*`DOmkX> z)Hy;f*@=2Od~9wXwkgYqR%@qIS#aprxd9AFo^MZ2_+7<*9?)eegy?gNZ3E9=(Lt>Y z*Cq{Z%g2FBerhpQ$6y=rh47|)C>&83cmUV1zLb4h8&!%P{LUp;asy@4!|xdzGX=L{ zii@V7p~kcq-O8Si^UHq8g*!$GHu_IiKY6hq#dTb3cu6nt%-L z3Uv4Ii#wl{V+ATxkfPkaP&A=;{mF}3d~NS^auJeOPO2A2xfN!t+oop3USw%6dox6D zu8$-r$iQ$Kcie_7HgmFqTqhlj<`*D-Ln0)8{Yd7HhEoeq0hS>-SqK@{87=sNueuMK zkcInTbF&^@mWqYdQQ8t@NM5?c9a%lPZ4#T|=DK%h29GJIcLkrgCcz((>xEcte(H2m z-#onp{oOm8u&^Y1qoF0~%%JjzbsmWqkscvx@L@lS6{A`GBRMnEH2V50;v=s>9*J*@ zT;*W*SbhHrGwjlLz>6Yns?3X0fm)Hv*MfJLv-PGJ@b;XFmKS}0{J}C(^x(l!KsGZCUt+?taOhN7nycad4=Uf`0sDoRIxTeVj zm_X7p<^rA2DpXY%7-?tb%URGb%O)znIH%tZuo3JP7_0|ZSfGc(P5=QX_As3%(V(5j zA=X_xoJ-T549SnyKx9;ym41)pB~5O@jnT^#H7_;BQ;S01v3Hj(IWR_Rk?k#+a=hq_ zrHQa~Sry~9u68r6HSLU>2kqn}uXZISqGW!$k0xBvjaFn0`yhCwSw`V@Fqz(4NkKjq z=;5-&QId6M_`n(%626nEPc(5S>b*fR(q zJg_|=Wmt)vmk?MQMYic3@F}xt%rDHz=x}K$lupef12T9V$c?Q^6kD7v1HDx4CKg6u zu)r;}-`KM=6X6f>Nluw9H^!C*6SN1Pr6?E5UmCu0Fg zqOuTfVJy^8Iv7vJ#N?Wk#mJ2CO0%frDwDiu6HH8;P1xhsxvQ0z?Uec>7%2wgOiL0< z%FgK4^|q)^_`VU}gZ6Sm`vUs{1Q)}+A>jJ1b4X-VCj3o}u&X#&Y}aCV^S*wbb9F+= z3QQ0tF!2)7_D?o;Kynrvx`$#ir!krLrjdzInqXs_oMO&r?q8gmze3l&76kafzV$I!p)Ith@yv!CLc?9!PSf}srUlrh1ffRX z&I@_daA1bP_MencVXvxu(r6>=VWA7_A)k`(xL-K-q5giE6PRE&Ml5=hTw|=!`=w_waG?VE zUW%C9!Zt`jtv|I>pqL1r^jPK8*NR@(f;RYeg)y?un{vE2QmCil{*%VO$%oP#H0tGZ z10Nn*#F{!iC~W3wa{d#a%}0Zx1HF4Q%x~Z@a~APqV@r}zbt`x&3@O=Lq`h!(0DS0Rhz}NpC^2Aj&TJ8Y8RIHq;1p zf4~3uLL?D4rSVj6KcTLOEDk@T@EfM&iPB?ka0x3KjT@WzKC632N6N`Yw3b-_8D}L7 zbMDDS+}v23NXRn>wQYZzZV4X1npg(xZ?OT@6x^%J=hEB@(Z-Yh7$;5TP8`PqMlgQC z6XnP8u%7eE2Qlmgcvl9bPJ@bMSFhb$XBJ)G-iBcZwKnkGNe{9H=t6q*4k|xWpOkbI zF8M8qs%piGDI|7N;9gn>pszL0$HjuNBKflaJE$6_sFKGm9r7Z^WcRI}(iE-$wC150)DK%7b0cOlVbN^z6)7tI1N4 zMxdI_fkbljH67G6-ni4z%RH*?UdyHtim5VEs(8LVB?9O{nJ|M2C28v|8u?aH1`q*6 zjRY<#G^CeY5@nV9<*E0)J(j(IJ3EDE0Cvfob*JqdkN4n;$)Q6}Tj;W8y zA?EK_g?1R{3aHxrID4aZ$}7Udw!Q(SP|K4}zNmu$x?XT=Ty;~-t!^F`ZPlfriJq&Y z*H-fsPGKabW9Ob6hsdJo)n~jT`_xxAd3sX7ZnesibX9M_4p(8oii+U?O5}=7##nrI zjf1u#V!N;7-dB6P>!3zfq%zXF4H6d5>@?WVkJ@grJmeLLN71CAsIEhJ;NXLm@*`?v zZXRPrq)ffa>ho9SuGz|}5n=P)Q(o#2zT@||e|-})wNmt=9CdmPFmH$P zg3|$d&E^=pK7bsb9|Dt!8u8zcX-1^4!f@cgao`ZMN$DEt*n`{1nU&ZNb`cG3tDFXR zb{E*z*m^)s*fmA7g5!=*zX03{M81O0ZGK#4PQH{wLzw)Zar<{pge^|mxW0D_{zInI z=REKL*u4csJqbZ7D5*$PQuiQHz~PJp?Vald^xaNN9S7x{&|hd%t;$vZP~iedvpegZ zH&?mcY%VV`vGf_BtE|4^rxV^gKtUrtD$+Z|xPI~$GX!F;1)Q$pv*g>gqA`tLx`^0s zTi+^##|j0Y@hdC!H}^(WON*-#*YGiaYPHk8Wr0r_K5Eju|A7ek6kQe4A^^Qwqq-tk z>jSLsg4IoqY9{6X*f>4%lXIhrHA63Wu)C;Ye4{}ldS*BO@xx-=o;Z;hw+@omMRI+P zWqHYPnz>>KHcAXi7+13K^SOF#_Jm5z9)? z2=&wH6Plq9rDM7eUfsr}u$<|mrsUVd3@<~Dn z3KtT>7K|XZm(^quBk#OMtV*5?jclb*Hpvd$3rIL19SomO&zjI9u9oPU5WI~Adfqyb zVr0Iy25ht&{68gP0QqpR1mMvtJcRP%%t6KlXlO=xKrV&0FA#o`ss>6aE5Sx`1gCA7Cfz_On~nJ(`^g$07+I@jmn{EMgR}+lx$5Jy+llruRI;@g7A>yQVk-A7CTq#|KuN-<_kS# zrVVH}OnM0c81csw)14FzrIHNiS*0RPL1LG`uY3D0+8_mmdB&X)p}3$DL0vi*OjJWt zSyvX)-F=f^?yr|DO{336c!5Y}Rk4CGRJ`cEXO@a-@4xZg^W;+Ml9BVCwh0UIb7{jNf7= z`VKIjjTfktnUDd5q3#SKB;tDkk2R`K*C_-Xj|EHbDYv7jwWei*!Vw@HT(;Z`cPb-d z@rD5S{phy2kldC5+qw52LKCl&-WcxzMA&vtJQRym@n2%LFA;_;_@nmw(=nihsL@vx z3DvpIQxmAf}$ReEFRG5f( zMss$)MV-s^w!azk#F`D#hyjX4-(ObEqyIGb?lHs+zJ_#-MTdCDa5fL3fb@bm{Rw1~ zFC=ejec`k9`zlJczuBl1*%mrndGFN2+x!N&QgTFa>#Fe?dU{2AU^h-^C| zN8u7b%kb|}O6sksnKQxjK=oYA63+>rvLa{4LQm6xUL`d5(!CRArC&K6TyeTM`(Cy) z(O_BKo2B5@&u7GUDH{Ke#VG$&ztwl2JR?c5{qM&YAXAR7qrSADT40yx?|bVIeb?W| zgX|5k$gRs~*m}bPGYumMc|jO+MYH@UN*;sO#8vDg$)R*WwUKN%0mRS_RrM3k`Oz2A zZ!;YQJPinFWmke}fb;f5wKvVG%W>c-tkPT8mr~LKVK(*t z^m_OZ>Fw^b5sVyUv-mJ-c(DcrkF>&}IbJZQR+(R{RLPQ~#&9`&j>!w8td^A-$N-mp znSuWTBVG2U8k-QYYGEU9 z=b3$;H_s4W5acHm)knD8Reln7NUv<^#W}5kz2^EsXt>p11XxVFoY6}~k#X~#hp2l9 zcL4AeYd^TqT70zw9NNWnqs`~!HY-6h7hYXKA_^bkq%FWfN%$Pfs<$+ z!>JwXYLJc3RZAt{ExpuEo+)7ne>hB*fU6L&V$hMWXm5-oAPFGy)X`?l-XNe8V>ial z&PmJ4vW{SMnN-5%iQVD~fo#&7jxiM@N=mF*gU}Pucp@*jdVEX@MW)i`q3Hlq{BiQxxY+iU zlMCWNDWhsS+n zBKu?D%XI2u0I~5Uun`}wS9;>Gcwz{7y;|kDh8NCV1HO-6v?^y{LIXF%HFd8TZ|6Vl|+#B-T99-lr@A-tJb+A11h+KT4=_8HRa5BU zCk)3t$r54RupR{@{;Qv?miA&K+%){o%QR@v^r|55B1rO=bR8D#+~JdFvYV!)ol7(3 zR$){|DM$xS`aCg8R`J|9{+hG}budFIc+PNKV|W@*UT4PEMpq}Si>ONY-@15n(>fwjq9qQlCE8B!TzHTEG0&`VKQr=XV|C4VLF)$qWUx5hi*{2 zx5Eb7m;M>xvxYGBWA97~Z|F8czX^ih;NO_k{`aj>JZ`=6Vbdy?lpK{Cy4}5ak!2OG z3PWqvY|}o~*hrgIySu-$t3}JD0d8t1^i}jThPywW6bA)EM-i18)u~0zwzVBf`k4~U z!(cb__vpvQ6YKBfx$;P(^YsDTJ7JV$<}n6(rm0lke&{*YJn<`^zl<6+I2S(KYNYtv zh@4ZiNPw{fHbo0L>1WJNZ?jzx&zkSFoZ9ZHkc4yH=ZHfj)<(_JwzE+#T*pjjNUu?$ zze(@@bnV7?M)fj+D2B;(#mMA{s8fe{sEO8oL)nRL8X6I__}MT<1d9GPj(ZLyBq=wO zD(}Sh(BC_Q+1e*ECwk?GktHS`zd8dK_LXD^2 zsdFfp5{}f$Y&S@&@?A(;v$cFgS*n5}O2A3HR`b|jDTqI+(K3?^<)Uy4X)+p~@f{*e zDfqO;{U6)3T=vkfQ(bR%=mbxOI;_3}VCx`Fg-tPONKlK9cwTJ!{_-V^W37AIFMdM_ z%e$jv7=K?toQx%jc==l$K;Ww1m7*Y>kT-vZaSQKy4zJ&)Jf)2#L4Rt9fO%vH$jCM)RKcM1Ch5naP9{B^i9)|quRXu}a+3D`2H+#XKv z>pA{P-c8^#*jsn*WTka@U1Pwt@bY!NH>Tpy~62m;DQDV#Vo(WzSDl z&CqAprti_dS7TUt?72~azB``9*VIya|7da~FKB22lk33)jJ>7t zj=Sp`Z3o`YYnVy>%Dv%42OD&G4AUW9=RI?tc5io@=gMHwnhPz>Zbq)kb91T$j;%e+ z@ZFlu9WOSqd8Hib2Zj!Yj*GS}_QizvIxP)1nimdAhuGm~^~QI?>n8W0D?ThL^O{x& z^{^J%<^bPC;1=66uvk$Dvkk6FPk4~F>#G{=?zVZu?|C1h`*UAr-cqOeF5pPSgr+-% zK4J%~V#c=UcD8<%Ute`nLXW?rFZRuoK}NamMRY3YIE%D|w6&?OUf%ux?;Rn8OP>!^ zId7R&Oio8M4S+@ee_?v?eZs;Je3e1X4vA+9Lf~`=uF*H_I9ujHav+rtk&F;qD=p6M z>2Q#B=~AK4f>{N(sMXQaF_%O1D2)N>ZXo9cir?GLl+N@Necw=1vil(aW$Z@l2mIK` z9GPr9V_lL1h^2t&WxpG7#)3xNm`MmT37E)a7E-?Ng|ROL=%4x{4`+w0W3|l! zLzBvJRf*Gtf}C6kJgd-r)#l!|if4>t_Hd4n%DWXlLZ5ZUJ&TF)&S>wQl0=N{H2`zq ziFBcQ5h2~1_{YpB_j6awZ`cw64hs+9?@-A@N_PPy&M8tNz$;EirFvg-u#DZk!?|F zKO}`QqsOhUtk|nQv09OK;g zo~uCK-fm8l(87S)_a_wyZA=su9q&A&uC|Qe#9v9tC{fx5LlwVVULnQ z(nx2Ec~{2$b@ddx5lZ)Z`Z{vM(hzZ9 zfgv|PWQV{jOd6j(!oJYqk0hXSQdNYEugd6hL@LRgi(h|#9;3vC&J}e&i1^}H`m58v z)ADcO!I%C7Bw`Np^vtz)af>_UO0}u#@2Q%rHRi zocN$1H(9_kbCMH}atnn6@<;$)TZV#w&SJm$`)VY6b=b}E7?d*7nNkh;+k zw01!p5B;Z3wT5Iop2wy;H!@Hz9ST+66-fW9Mea#qj^ zb+J6vL3grKYWp2%iznZuFdc#fsr7e4%ch)UFjLe)!Vuok*>$Vv8cPnw7^|U7ciM$R zDm6b#LcmqH(tt1;4DBEb(LVZbe3e?|X*DbFIk?YW}6>ar2{OOKF_g%di z8$lBu{&>P$(T!0>EZ(xzcUQ7I1&Q$v<2kx;cw$zyK0rkn>KQi}5+LHwC&D2DUjcc~ zRKYWST!~!!0XF&+yKBJk>m69=k9a#6L}Q1pwyba=lgk4MyZneR7DTx!x;U~{p!#I3 z)1Sl#hQcg)8aJc@xUU3Mi|j;0;QVO7g0v@gK5{`w?j1hr_F;J%)EYp+(L~89;#2M; zH`;BfYFJYC{~XMM|BG6Cz)e1Ziukbys90->3Pen&UvfP}O{m)r`wThW_YW@g!6nFPkldZ^!6D#^3pxKb&@LIfTh8k1K#L?FGj_lL6+t(ix9U(A zA$gvUN$J2;Zy^%Je~C>k-+kMfM9DUdaDN$Vs zF851zxWTl=B6sWA^EC7pfa-6Up!(fP2<^Jbi{F<=kU>|fvx5G?VS3AR1!Rce;0RRM z!OVmKyS;AIWRPO3yC|LJvc~IB>1#DR@w>)62!{~4D`x`x1uLsGh%b+0KF8WfW>Tv~ zTP${0j+?%-T8jIq0z1=^9v4mjSi)pcQ8+4;jxAh3Ie>XnxwC6v$uNkN23D)X^`(+z zYB3!PCNdq>Zq7J`WgaX_z3*F+7zxlr!TjJVNsvi_AcH+FoA^Ql4*DJdvI9kfanZGjXNvAAf~KKaE%nw~3?a0l?b@om09S~3jZ%5t`x*=l8}-!w{N zQY!xU5leq%HhWR&vv((EixzfiM6)jl6gw+z^wUq;XmQ{VHCxi{qso*XOBiZ*lft;@CqtI%8IAH zSB+pfVrq7^J7N@I`OIFYY?5E2u$bOxJ|EW!G?2LKus*OwpE!fcTw=~KeusTD#Ci^)XW6t@r#bY~@jY>^AuQ}VWuaku9FiB%)u zoP320Uh~mlIX8zBj&hX(CukslgA8}^gWa@rr?K+dp)12yGVom<;-ZW+4OVX5%zUu# zIevaaznbf2EQO@FX*q%fh=Z%1LIo+|mhsV0DXB;%zfCOrG5guw-J4@_U%S@0-@9E> znQHy$F+?(QbHMIe^v-8gM&aUXO2a)zIgBQCO#|4)T+3TubjY)QITtYtle>8t*}ch`9bki8TJgy4#5#^`275HlMZ9jV`(LNlV8@ISr{#>3*HHW7! zueLWnl84SLP?IW8qygWUFz2Q++_a@Ae#qL%5ML<60j$^I!7nS8u_lEQW{E(lahKIp zMq&HPIVt%JInl-G@L!uW0R3uj+MESgdL3Yh7QSMUwpdZnE(-IF<~jWz=j}8LbTrA!vx|lqxDCBH z-VV%h%pcBbb4A`axI3$w5$gg!9B~O%E9HE9v=%Z1l`&f<8*YWRBZmTMkRxX%{v7PE zDVtYGmAFk;O;ON!(TTc0U62_!s_#zp&`2~{EmLM|N{I*f&)<~SzW*T{j}x*EldDDY zS^?RkuMOBx%)7v2)DXSp{0i(+UJ(yI1~jjXiIg$MJ_56X77!le4t?4=4hUpJ6hXCq z&kHY3WiMc~*V!&nv+%>L4+D3%wDJ(-6E1^BLXEYD7)S+SWcV*Ec>X-rG^nuf7)~w5 zxZB<>FLvcD@W+C@-qLq?9v=PE?^khEkTuzsu{r(@M}gi`Ym>RmsH&~^vNqzo4DpxS zyZc~yLTf~;Ya}K#g{)r~tj4Z`s;UYrlr<)op;vZY+zCMv z2p(qIOJbeQ>6QiPHybn1P|jIO_c1Ne(3H`CB6_Sr9R?OCYYcx_sC^e9sJei0%Ic(tOxEu(S}FA_kj)|W_KaINmx{VC>}4iK zYTZc6Brj$$cEzv!V&+pY;KL*An#FK|**5Fe@YfFj(LOH!Fd@W>iY-(ZUm+sJ+WAPv zy}lR?1z=*J`sGG9aoI|J{bnxbMm^6yWFUyTIUKr&&Z?@)Pr@DGSRDI1+ZT&d`*>0y zN$KPnAY@CpV6LE_hc1L=*LYE6+GgZC`*+vH1U2^{gsk=Y>FMNXYU$5<^bPZluMN>& z;les_b_%C_-eRs!H7MlnB&_>Su1$Hi@Oi|XS=y|IGCDg`2FQHyO?@O zmT=-7K%QGXJKShg1i*1b7x*mo0v|GTc613F}4=Pn<(sJ zRt8(M5heiUrr))cjdqu=lqTo6(=9**ptxT7d!zEN%e@Z2f|8P#;FXkfq6)Y%{_#~E^Hf`=@cK` zOfB*_U+YDPZTX*=CNfmCc*V>Sj?w#}8i8Un?XV5O>3*QtUq$gB>vC*fX!DmkpSepo z5x&T)58%VhY8uhA#}^~^V0G!Ad4n8@u6G<2UwlU!>bNOdXUSL0v^Ns{+bdsILCtu8 z3q5mU7;u(40poDkSOW9d#;JQ;KN?n(yHIKbitjkZp|#71>?%W44)~^H^%5>5+AApD zjqD_VwsZh_$MgcBY}v4wxmT*IRn#{F=o~t?K|uzaW?oQ%sG{QU#u2;;fgrT5AgF?f z%AP;v{`O_hr>2FcYE0mftwbOK>7Q9UnKM9Kek`-FQl%)4xl!GOhKsueZxdmpa;-W; z9A&JlA70;?E%VH=>LyaY26R-(x7e^*^fF@UB3u^a!xH1Hh-lG)XX|x?#(~gcT1I0y z!H#e3A9rE8)@uOA{Y9{n$1%}RFr#$t>kl%ksYFhfV1f}%8f{B&I;f`FU_0-gcj`t@ z5!>yKjuA3SER5^nBzd+~gZzn=)D$jcu@0?BOW>3-@~z;yQzOzOS&CyayC&giVj@3M zf?SfKI0rp_eLYq*%#f3eHIxONV1EBFk|}p~W+Y_$VY`?ZX^iU!W@`q+on=p(Hy~@~ zhGyxgy32IlTotW{{ZN1O9+B`9zlxRsNkF#06;II3sl5`%l{eY<J7^xjzF{lV@Y?n34X0vs+U=H9d199&LmW!Lv<%{^Em}(xNZmOG#XA9W0sK3T6 zHNt2W*E5}Mpr<7lgtsQu$ji0I+jk9OrwCRu`a@pi-jU2>Rtfo$U7PSz4FOJ9vWP)b zk&9v?Oop~z1{yPfvIwLPbZ=%#*}k!srJooJ^H|SP8KQ*{+UIzDEN5v(j?Op4FFcG4ZZSrnM{9rO1AhQ&irs&cAXR0|VZ{g%WcB#b_wnz@KlO z4ElVMZ^pDCR!50xl#3u`f+E{={_(Sej`p8ou*y834jKe>==tTOCTt0JbUwv(tEFx= z1J90m_qc@IgA=wRvna_*Mb;>tM2T)8D*2<1MF6DI+?ML0;p{}B@ln0NSSi!C3)J&_7u7C z_Vi3u;hxGdFPzmLPyv|D%YJZmD@y@a`a*iH6dElcPA$T?C-#e10p7uYqZ^ZeVdtE{ z5qtI7CwI%%fYEmQ9&%cToX^f~(FYVG!wT?NIp0avXu5B^GSQZ*ob=C-X`d{ z^sO6Gp6(Wt!US%;+sNjI{-58QUlHY*8BJUDMB4dyQ|R3L*S=BrXw10($HZ$dB5bJ# z+b?EcHsdDx71>H=`W_q^@oQSNbnHT|t>LF6=Bkmltrd;hxZ+ME zXa^dpqN=F5?c@|Pa1x=>iYz!PG4Gc1VsQ_==%`-95TvpY1vF<~D_ z^Uq25U!-@g6bGB7w=Wexl@F{9ob@zxU-R|zTENLvlqR?y&$A|SjLrnCWCb>p&C^dD zA$J20X;J5GeO^~z%^aoSgaD&UTCRgK?8UH3kG#V=2>&xUw7lw5b7l!9cc zv&o@ruyu9;P@olhIeH_NRkW8iYW4I_NB?Sr=c?n3#`YJrqWA<(=@3;NtA9k42RZ zVuf8f%P8Z?q}oM+kT4s2Gx0^V@oo2AyXbBJv7}o);SmD41~?e12KVqzkEa=?!;^$yWr+IK=gt_%lojW!X(uO`jvk(r z(wuph9GdzHc)Nnl(2Bo*5ybz(S*u>Occ7KW(V{Kf-r7;ksqc95NY5vC$J|nP-O^B& z6Qi|p8&y^;!4j||XD@iZs`&<4dr4xQr9HSqPu!ku%pQwj-4ibDXE`MJxAgcfgGpP$ z3&WPQp`#F13FBS|`pqz2+RST3iDO2uH)9vOcsJHTb5M%b1Klz-mo9cM&@6@YeUm!< z+-jprj5mIaKij^Z1;RN`Z04U)Ume50Ei^^4AOLHrLdh?3D#zl>nz)`&f!EhRGhzcX zU+FP(q0cPP#wKI}S2>x&jTH*He(n|ADEe~KPV0Dp=GpThyWbm+@dwla3{f)n9-f^c zHdUeT#GS2s0Q~2O-stmM?k;lM0{RoE79-!BC5Zy5c;KZgdIvC9;~G~)4jkV|t+4CQ zb|YB^*l?o2A^;)sr^v@U)7z3?mv7&v6VM-C}#5@%JZ30vQz?`n$jIKKqK#)||iBKw*t&@tmJ}}(4 zuA5Ra;+vk1cPGC&7l9*GQjNvCQ#o(DXVDvuM_Z$DPxdxF*f^qYFSxqrY$fuL9r$Qk zhVwS8UB?EG^X5TKkf5y!JdQ~ZGMeo*RZA|%m)qTo)Q2MQby}2K_l26OU{Mi<5FrgW z9ldxfId71w@NGJ*gy<(D$2$91XT5q*#T7WgeYB+Neozs6+cvtANa3#rwl1!10WE9} zwn3`J#4}g_cz@uclJy4A2EK4=zq?q7vyBvlW*_+Nzg%u(F$(s88n=fd!aSYpjd6z| zc8-;0{H&6+q=+6ur?14=&ui3n6Tf6hG31Xr@uHX*ct{FwBf;eNTte?foBV?x;x`Gp z!NQlg2{o~NWjGGmZ|l4*7?Kfll>G>a1k&0?|B_JFUwL5kckwe;7J>|Dcr;qQwo7YS zK6{3?jcRFwX-1QTlkRUc|H zCi}t7|xT1?(IhfQm)75+b(o6*{(7h(8Q)Re3SC}ty4Kb+A#eEj+ z(cH=?&2c+%3xvd!#OKo0QJ<(7UJV(c5sGsG1IaZ;L^1QQUkF8<#W}?~-jXkqm&{P^ z+wHnTc2ezTY~ZCP&Y}=8H$=g+k@gCG-9cGdX?Ftr0${MF1ts2~Q9um?Y)QBk*5Evx zcpaRIwJaOCDaSl~V z8~*{1Ho%jBW&7L$XwC!6$M;6*qX3o#-_c;wIXsG!ktniLT(!&h4(N_(oN0VhaG-X# z0rXz=IU@5Aq_uN!-8$F)EFKOc)H&h2YKBQdN!@n ztT#=J>qe5K&!mqVM1ABi9G1wPSy)!EinDq+7q(&r2JDXAr~-;8Cu2YbirEkzBX-45 zY5dmf6{{7m&UsdDh19gE@adS)b)7GeD{kaUsa;x_NK-E$PpTe8>LG7njnd(sEN5lQ z=@Rt?(MnE3nCl8DfGIal!){O}r=Q(Fq)4<9S8clCxWoOf!68Uchmhm;=r@1?UVz+wzQ5u%n|sBH2}(gt#}sE*hH zm7?FQYTwB8do3{6cq0u{Ws4BX$^KpoWP&v{_L0R^KxB&Jwim1BypHzsrg@6+Q@`m<@5_{`u zM{4|9f<-9t2LSCsL>*DIHWY)=_z8)$UM3rAzXcM>O(E2SQpMmY{mo@=d)#Yx9tzyZ zkx4Y32WvQvV|Lr!YH$HCE5qA-%sFBq0A88o9Oi;&hge+b=f0(t5u76%kavL$R(z8~a80ll>m#eq{Y*imm-qLchn9HZ|K!S@*LL}}SGQV(~{fhH)@ z&ClYFudRCu;L;u2RedJXqW_$H`Di!Iz<{v64Pbe*Y6=bpm7vAS6<@rp3S;sGsv}o5 zRu}oG+$0dI#}^{eLy(LTP3>672NcVtD+}HN^>ms`WPiT=iGTrWZpX0K33k?vH8maM z43T?#EsJW~s+P3M>2Q97K1me1(%OQDolK3e@; zMtu+#B=Vo!wrz?Q&`3?wbSdi`RR;|=p*le@r~wTtTN8SH2h3pY#)EQSHX|hBybOl7 zKm7CaS&Chdon~J|C>Aa03mv}{-o`btDiNS~@ZQGAEdK(k;~xgqmu(svyJ9SY}MnXY{bgt3}epax?WM!QxzuKZx)*(U#f2Fx|JiP>4A*p7i>i0m&Ud_LT+bJ!ZDkM|gnKkH1V19Xs_Y7oqH#F_7vU0WBipkvBrMtg|tDIrmrJYmbV%(p>fL^SF)&F0J)$g>c zi}n;&+_>M4jDC+VU`;GU)+wQHY6TOn#GQwSK3Wcglz0Lnl4BB+s@#XntHY?C416jM z8{R2qcNojRKGJm*uC#Hihr9jjXFAP*2qbp>Z~NEEK)hsVGYHf7;V_gs@lXcX zy)pm?`|?Z3>`3aylK@_sn=}G@dhI@Zs;H?UVw@nJ?u6$c@+h0;tnfz>s+P#QG47ZP z7wh_q=)y+td(>SNb?R!ct}}BC0MQg`v3veVAMePK_xfH`8pZs+d#DPXA>v63_n{Y( z>fS)(3HbWlU|$R0vp!o_(a9AuD&J<2EvGea+CG$S-T*4!(#_Z^8Nd$r?0 zz(^^}m38{loA83HU`&GEelDMcfxVvlMMlrPmd|e#1((BPSjitf8&MeD$c!WIU8OOc zb~|c4gDUhZ2;j0J0rd@hD<@%V;ji&G|4W=+GY_RUhW)xG%5TQgBPBL;t+mci4^Z3} zC<-=n?(&uXatygB6q`cap^eFQOF&(US)@Mz|KRFg%>J1jPmMBPbCV13ixivYPf?+& z0MNT^q=qZt7uBd>5PtM1u2`KZ6*^HWNVm2k$qv(k)_}u~IiQys<6Uk}uA_SkLGCr` zuzsp#fjagwvgSJZeDn(jqj1(75~+;9STcYLMJzR4_^!~g9aDq*3`FS)T)SRXd13}iW$X}o2?*J@=JX9?RTKeGDoA0b9s;7QANG5OIdgY%e-2*F{iNcRcIvD9 z-s0X>_Oblng>bh(>~_dw5J&6JFoQO;DMD!nj7}|vLV{WI{U*1bC5Z!nkwLHTF1-@C z;_#Q@a(IxQ4U9eE8Qa^BI8k4hJ!QbL*7C)k%NwsqfjNk?N3N8indu_~cx-H=_GjYs z{{pqt!o$Nd$x>8az%7!`tKDkLFSdd*gLw?pLhZeAAj8#+`n5X__ zpc8K9KDTDesvrH4jK5f#vcY*rfqnsV?Ew~bUURaOWIWYf0tBtCR0_Ia!6|WD^@X35 zJM(jeYs3vPi&G;d(w^JP&)y(4mG7%Qub59NxZdi`H{549nD5hb3;}Qs7ke3hwGzUyW!Wh4NPGY=GwJP)S1P15AO3dO#C zYvZVhy+M5ghzdl?>AEkWKhIw+4m7$G>y@8ai21e8NB}k|gS7>_xJgMoUG@{0?|j?E z@Un7<8{{@?BrvY*n;-V`;E$Y5hw%!XhJW}UlG$M?q1ny$_uW+}!X;#${Scrv;2f(* z1)-C=uKDjlo5YWN!V`n1Ah@;d1dTgCYl|X&|JB=uQ6_p0;eBZ0<#nu&)?vm8`Vbn{ z*3)IaxMrw#%fd~Ew7wEbTL#~c$F zqefhEbhtq;WV?+60YV7~TRd9e3pZXPD^~%y4@q7YZ-37=nySK7Fy&~4wNMonQRD#L z9^qs2)LDy6chvMH&6kbtgiFn2{rr1>qWTKtSA2!;{s`{EOnzl+aGk3cU2C@^4!X~ z7LmYkIhpd6v3X(ebboz*udm0snayXQw4d&ss$?ORH?s#_a;^Mi1Z4wLZywkaf30vq z{-jM*+lVTucq0&3HnBtghUzR&NWEw{-eyIP%P#{D2_0 zwre!)b9{rC@RPz|$?`c%Omx zot-Q4m&=1p2xv%i0_=`(4TChG9Y%hD{=st0Ss7|PrGG3O7tM@V?5?x<_XcX>Cip-@m{n%Q z>!Va6uhIUj$$xN+D)Vh^sl0su5rxyqN|P4*LVXEyEM-f+yy9j02yLbjHf5WWqNC2( z0*0?)-GG!ewK=8?GI8x=u|+umt8si}9+_;oM`v0xUFJlRTY#fhgMkM-+(usS+@H8r zIu;gJCz@^j`XLlyy3)xY3e{~tN_SIbNv)aN%9%+v1Qf{dq*wF=;t1dOrg&ggp!4{(ST-qr+Aq@kMQ@Hk$VvX^QhG4%-J@>wuh$Y50%CNVfa6 z<|gOR5|U0`zf13U0&Mq#FNSWaC}%&D{`Tue!9rjQ8Q;3hU$IgX9L!^jvZxgy}ovp`jPO?)n1(;exzubB{$2+JiK8R69|uhH%KPH%?{vppRbClMQ-b!4FoI2Y*g?=YhbOso+yA3*e}oq$ zg|6)gJrlvQK%V&G$h-mLDk%qS*PzMuVBeE}MnfIu@%}p~*JA9m-5`vyJ!E!#8oyC| z1Z3I44$yEoy-#+S8GSB;{YxAwKn~acR}Z~Zz&`q(s@(LQhktgF9a4KGUDt}!jv8=c zz+H0d)0-6w=((uraoLu~`awmKSVl44H*wd)FJ~xqD)$^AcRPWz(kaiD=j`v4v(Y_i z!nQh1A19Z%^il0A1FMU;OEJnX=p2^i9rh6jf_WAv+#9!)OfIXEP--1hDLZ;2z_WQ6 z3}}nQ!-0)dAa)I<8D&XDbub%FEVbFu{8uVo(Oyb}-gzt=n!*_8)yR0>TFQ$!2U*H< z8N4kKrP_pU!aZj+Zrd>WFE6dI6!8{)xEHH+T21!XOa}ZR_(WRtsolSy0}&Hw*{`Zs zYieO(o$_|f8gSa%qnF>jzdY7?qNd$RY};y%J@trRax5ZL7N1s* zk)oU%zdu95_Drj63MZi0mP0fGI?Pi(ze;^AW%fG}$gRl|-6~<8WH>cbiJKwD1x5$}F2^7W1ew`i|MVT`E;HOU z&%ALDf}zhW8AVTO9aP9sgo(0h|%?KFhPRS`Hs|fVB*4kXo=eu)z@VDC(%PLP9Hqo;HCYofjj;5 z6iMspSZqNFoU_SvB$&Vm4rK~oKTOGfGH5-;`4rrnOnNnr;5yu@<3w}{%Q`%0a^ca* zp#FAXmKFtI=o6n--id+%p;%-_AOK)@Qbo<$=far@?%MQ0)kwgM4%LqRPT1>r#A6Iy zBlr|69Nv>I`{lOIu!vXe(7ik|0CC<3BTAw2BZdr)z-Xy&%&sJkeli{F>xT~i12rT{ zu`xei@A7oTFGG}pv=iK+arSyEdcZeqAx|NLB|b}By;o}mTOpU`;Y*rMwyHsxAnW{o z8`Je!ri&pJm#>=M9ny}1jyuK^nR?JYS#y-UCU%>@Mu{c20Vo0dhpDb8*ku}fQu&rF zn=OLBYezg3o6SYhmc;-^qZHuMzOcDk3 z?yGtLfWcjDFN6-Pmz!abV5@dD4&bCB^79V7qb?bwD_M{M6~_Od8sy=eyg_^-g#BSw z_T8j6P~wafFM3&bfcF>tX#;I3;o13PHxFVAn%o8kX0uZt5lz=fJ{RbKOZX`zBPQUH zg6mXo0!4~rxwCuq z&~diJ_UL0d1x z;M=b6lV@&j(jxYDZhQ^Jz~1Npzc8U8wR8bW%X*}%h<+jv(Sc9VHik9XseGP%{vm!6 zY}8~^^5sE~VBt=BCBwTgd}O$h#K-hV+CnAvE_Lb_h_lGS4A-wkq4%L!DbwS}a{E@pk5@<3d0VT5vr_ExjaMtuk}6K#akS z;nU#M#&tzzpn$O-9Qa3T2EBSML~%wbSK>5~rc`OX5(tmh4hm*n(*yvKX7S@sD*4y; zdS1@4fA|mfy5zmCzz$JRnAX8XvZ{3eE zKB?o;*t_|^TJEhxN9^_tJ5RkIf@~Sghl&BKd>Bi6P;mhG07Xwk#4zvq3Hq7KM@wE| z@xFw98;TJ28?410Q?WqlORip35fzpP5;GUK`|8ZUBIVu<`6#eWaUAphIB9sKf4(>J z@&7n1sgfFkMLHb~!iW^;Y=Re_4b03u?qX7=Hj-o_s9XC=TNc=dmAZ9f&(h?Y+jA9~vUFP}OX%t0qD+ zS6w5ul}8->(8!P9cdHANCO{I8!V#huruQ_#rE&U@-`pwHP0!4&Wr3z%Bv!$chYnhx z^%vm46E7bJ_B4s`Nn%9k9P@9}Wu{ox%+Xbq+;#oJM0zOx6$OGp0$f;MepHqX`kWny zfS`X0fU=t4hx@&Dca6QHjOwJYX{D?|ZOFl`IJpAT#8`n0;9^v8UH^SpkyBpmm<{@0Mu> zB5I-ZCcX=yx@)C_MpGrr{Ah&zqiRkeVFshcpZZ6&_=nq!1Mw2OJa{=F9>5EPZR-35 zjOJL5#8Z!o=Oc6wK%j%+$W8gq?RBO~QW|K`CXc+`g)nwdQm8MQGMhk%E!n1?XCd=3 z06#4!vow9fAzy}-K$tE+A5a-qoLGt8!J}GFK zaQ?Aze3ye++iu_~l)^}>j-qhDtg20DX8j#DqPTG4qyI+?*5m_yR$ZP_2n}CdNBsEK z1cO_boT(9?y!iS974N;*m^Rnyg@S&j`daKGK33%qio3z36WEdr^k(AfPq%Z~g}usc zB;!GxH!h!|yF0uoBzhQaU5age3t?u4FeI~%#>IY$d?JVmI*vrBgTEp*=_1oy9vUM` zI660i+%y`Ora?#_K!ebKw=6fXQ}&ff#4jLYVF$T1~~UBmK;g zcxV*s+K4SgtIy*KAQBMf)Wk-7;)=g5sjOG~B0|Ax{2WfP13M7g^;L7URWtGz_H@0^ zF|Y}B28EiWhR_L1blsOYDwfR(y*&BV$?9ihLK;ajba^qi-a$70H+GkJzne6ov1dg| z74*qtPy|83=WoR??u1I{?UkY}YiPSKwz+c)?7a_^B~?ocNis zPYicTN4AuDw`I;f1)d{D)itb5P}`>{6b(^Rl)rZwCRoOO_+ms#l0-)9%GDo}O14lZ zQIA5^^x z27pMVJqRrLjCDTTh76w(;gpT4frv(oj8=GqDp{Kgb0RBLHzK6=L_}2U89iNY3tNo~ z{^T)LS7H41`q@%T)PK7vdGYBj#4}E0HuEImztnLiR#TcK4DLAyrmMxaIEgSk%{_=RT95zFC_oM77gXxAcAQwNgg zKCymy-53I7ESh*U04$vLrw_=BeC5ClwJg{N^veoTm`brHny6YWVc>Op4)om5B`qR+ z_r<(MX?fE`n)D*dxn5psjkr*-5u8xgW6!@EH-^$ntd`bTG&+KCN_zj5YMWD!)m|+- zoW!gy;ln1WZA=htM?ZRFH)`sT)gf<fuKhw43|;xA5!#19YiuyfMT zCuz4iM4IShNK_pwJo|n9kkqbQP)jWaEAK9a#+NcKcW^qz1zQ&}9E&*+ody4|z%=f{ z6z9+Ih&oc^H^q;Cll#dt^I#2q+s;*tRFxXt?k6nlV1e`R>2QPg<5*N@R)4lbE7>Lu zRu+?>bQ;~D*;D8Fu_cf3Z!*2{e2`rhO$@59%9G6L3mq~9P02foj75#>{$Z(|cfah! zZ^)nzZ>jC{73^Qp@w_|r@LS4M7LS>KkG25Z#|3>)CpCGIOWas;n) z6;`52PmcN}ZF(-ZQNk{1F00sY%4yez>`C59IQyFoLol?@VWRmn(pqqPJKp=cR+~dC z7?dCXWvA)e>Ad7QnE3{}iQ=8nygq@Cl_qvi;W$o4CD z2a4|I$C}%gSM`$x2gWDwL4s8nkCzepv3QT*j8g<1`m)FDGq3WpDHyeCDfu`3P7}kk zG>~^Abb&o4zI@9G+`>yQ1=|io?2<1Vjyr@&dZqL>Zvclr&zF!}QoB7Q+vNlEKtrBH zP+E@T(AmsjZ>Q;|yOBN;J2WH|4If3rrz#dp`}{@{MZCk|-c{SnVp3~9oiMTyrJkBJ zZd-dWw4XAN%QQOc9MZlrHE>L$FhD7JKH17bAS&$kNni$d7V~n)BDd^2&54RClPHXb zTDnI((M>$)=M}=8TX^jXOram#C%CF`XE%lDv=h_Gh=g)wd9z7B(=JWhoyvBAN*NVihIX>VV9B zR@>Oe5rt6)Mk2-aD)CtC(3LeVvVuSLo-C4Vy78Q8soPK6N()3a`J5^dVS6mw`tu`?o|W>Jqz8MRYOY^X zqRVEISkZGHa2k!-=noY`9KNlKuH-qq9iund==ng8%W@DXq#XZ518`U?* zM`u{1n8Tk=i=1GG4J@V;!(HaB1I?kLpZ_?F68WfWQ9r+{aP>al=0X{ zruo-r1h9S$Y)F$|ve{(vGqgU(%Sk-E9GMIpD|)W! zE~YSC`0w8Ky70S*4LR373kw%U<@#08u6R(LmHvE@+ZMMgzU7AKEl`Xs1i4#xm486E=Px#r%eR~dzCp5%R8zaFdQIi#lt;{qu*+t|Sr zBI72+z#1!V!@od+*A#+d>BgX=y-)AHygLRBLHe$?wP`;Pbi?)hA@cDBSL%;ptPeDR{ za!iMD;72KomSbb(BX8AxuEU=$$%`?|z#6NC3|+mPbORPRy@wMr@(;^dors9cC@`Mw z$*VaCbJz3J%>MDSk0xG(MQO2jBbc5dxjrz7-b*}!u#964dj3}$WrvIm1dZI%-Gcj$ zp3+xlPOZzxy*q1N*x{Xq-AxDjn`8{eYEL@%B3&@1M?L^pno{?4qw=vlrZ@r}mgs>& zd)Q#cA)Ok=K^7v_e8f>>THT3)dHa$QLtje8*xtlfYUK*%R4zE6HkXd{0N`!Hk3a6T zY4d;3Xl`a9l@wxQC9(--5K1XIL={A@rXkq!;Ht8OUhx~>d%@F;XK&2$rOY;lrc_hK zCx$b)Yn!0`v_Niq>+yf-N24Z5b4I%sIoe~294BPPyNReBHfNsa40PU1b8WrCA?YeC zR+cF|wx5j8y$gtWV`oFUutqwKA9L@n9&HOWPcOclbVUhJN!`L1SI#DbO6OC-sU#b- zqvXZAq`<*JL9MGcDQ`&#=^E&XWYYotb|U_rYI7rOU&{RY=mph zc7iAkPDNvlqhnJF+~CMrrmk(*mCC4Lc!dteX^JK)@+4LMpfhd$2`q<6>0N6}a4oe; zNoDR=banVs1qJWJ$r&u6B@keBq^u}Gn`p3jw4PoW7odU>oJT@{3WE^^J^gH&{$YJ2m{9U- zGIBnmaeYN`8Arw*v+1sd+4>vIWp`(X1(wvX`d>I3}$nY8= zd>Q3=ek7vZ4lkMQpG-~zKndUfo~_R05fo}3j!V^!m2a(}&QcuZwEZwY^ za4G#PmFvT&;f9I7+$&+hj<&tEovJ$(Tv zj{Sl8CsSbpN34A9Ewm zTLz&4=RrcS%1;r^$W|cIwMVs=Vp;whm?{#1F@=@iNX)@`8=KbmuQW`bo2&#cw{K53A~FLYfwP zUVD>%<4@K-RFaS1he7(PiQmXtkOA8Wzg!NwV!|`z()q+I)=u^OeS?gat6OfPA`Dc? zWmNA}3Y#a;IQymB$DEVfPN!Wg1NI`)gke_P(#w14tCYcu+4=Neq~Rl7O9gc_VSr(< z1=n!=AfiHARSU01fT`dP-*G2gbba@*jWv) z67LLN93x0UYlK>cd4r=S{n)7|piH!*3K{^r_`EjG+{t1269?s^j~}8_>p*{IT9)x_q(w zlgpj+0Ag{n7A0r!95bS?QF%B?PTr#1fATrXI`cN;T!{rZL%kOr~x2 zf?g&p>+St1QU*N|jnz@x5I<)#MCjejguo-7njFF$dBZPy+nL26h|e1RBQ3EGO!?A- z@A#z{*Db@N?nxTO?EH%ThQCvRbN0p4>~n<@cUpbw@LatUSc1Z( zJ@|bbIhO2ATGI{=bf|8V2`T~MVC7UgKY(|DY_HfMWy-{3VYL-fY7lm+T+gsoWBRRM z_5f&eefHvD38powaBz?k$OVKupN<)IEVGH+q>yygZHwf(RAOe}A->6tL=+XRgC&@f zD&{X;R6V<8r+x#FTR|^`B7a~+)66_N>fQ!1O<$k!;cH!EZy0~iIgOay@g>F69js76}=6 zj&>$4M1SVK*1BG{?U!>sXJGd@rCT1t(13q^W8)W2mSUr&EKXLSMEg6t~h(zUjwLBczP(^4O4;g8xHai4&~$PK|cIb{&5W0_arV zjW7%3&n<)tQeo3Vzv9s=i6n5XkHi>LUwmNLA9<&vP_Dkej_?gWauM4^W8^WtFVl_-tC05WN7sq z3_PN;E$~aGZf+oVO_dOiN7Wo7LbgYyrJQhfK z+z#qAnS^^wB3t_CZ_-wW!TCU8=r6N!V+^~fq<+{ZR!)!LN!wj75CZ!?p)a=#d43@@gQMkC(z)u7^gqs_-{jnr*<7c;E6>{d5@aU_CfX{vE-T{>aj4_(3(SF+k%XeIHz%8<5m z0EpLEGI&& zm!>@a(!EYOWeEnO>tG3xRv!xb zBC|AJb71^y+$H~3N$O!)SYx@i{F@K`%cQDSe{rh14cbo_h!@jbG#{^!dHzj2nTO}_ zj0%({&dc(3K~M?43FZ{tmyz|^E+ihZz|ycKcF@!J{SlS{^6`$i#P+PKDaRqb48`GM zs6nEB74c=rCZDR`mLQH?bZ>4iSs}^Hwf}>SzYFnK!k^+mwY|g1i4|CuNd@nta3z82 zNIh%`VLm?iz;_AICHy~7xCk}k{2D*BRl9|_5)8Q=fZgy59e<|NKnwUoHO*LP5O#xu zY{NH-AHiClRsf{u=ZC^cD0{9Iyu}r?jEOel#_uv+ZmnsTPk{}%iOTTVW{VfWgka_P zn&d_~kzm{iz8zEz`X#Efksa*$!opnQc{%-el+um4LLzi%W71!=%JvzD$2L8$q0}+D z_t5h}wR-h7-Yxnuk{wk#mZ@JKQ3J=vv`IsukN+G%U`{(h5U1H_tW(7SBL!#B0Rxz` zrbaN83po#mh!HR*h21fA!hxFa`PhwNM@NzAAR4S^R+Cu zO10xy{-S*`$WQuI>X{bDMt8YVc#ylev56W{#a2%0Cw8hxb>LLmNe>LNk%pkSl(W_n zhyXu8z`wC)onspgBQM?R@Uci|N_LKU|2fRXob6OO?bKNXv<)zzbezuY;-xn9!*b_$jN2F*@8RPL?G${6uBsb>s|f53c#5qzHe66`(Uo zR{?_izMSBdx(!TY`!&ZRv~!p~G0aF+_;6P17>qeMeb1xS>Wq8QNRnWa)2!Oc5_N!XHpoFJN8 zZ^6h?df5il7g5#QZ>bL1;?b7**;+e51=Htd@*m;ON~bhg^#0B1&^`eGvx|6Wj1J#G zbSKvsA;`iSRMkb((uPiH0f8Su8k^PL7igmZ-fp}1ukKY0AwopzEuR(EM1A&2%iRd< zY~HvYG|S8tcm4X)^j0mB@%{uWGTr_Cg4h@;&WWBsX#zZb$bt5dxpEuc*`Hn_B~Z#% z_dr|dt}c=Afy{e5QmH5@&Ucg!MaAByx2-fu?3fXyw%n|g7$kzv7)7G$W@!myWE8yU z#T&BgTU7%BA`;Rn79;K;n>?4(RkgO~*EeQNg(?A{b3$AofM|qu11GGM=k0{^E1{o> zqEQhw{HK1W$@NT8rg>93ho@?dMIKcXeQZBg9Jn)43Sgq7a<{B&-;} ztG6RN;Xd+Wlb+3k4*YEvw9e!Nc<<(DuKlu}_C~!KfYHHH@Ux}SvDbUmYKA=zBRVU^ zUr=kfJhw*R7!Q8`)57Al=!71_`9NZ$c7feDGV6NKv9+Yd9aG4+heP%E>qzRJ+Cill zNI4(Q{P3fHW;<*yfXK?h1RP{>an0iFvqn`j@oG=^o$@w|mlj%UwM@E$aUW-qkuJGuKQ(3*t0f(*vM%=vtwS$({|& zcIe^TPqG)rwHnT?8BA0zWRRP~$LuzjC*=L~W$EgY{}-4WpX|dD_U){4{k5VSzL|YU zR@oa~Pz&(&Z35*XN6I=Q?!ku($H;e)5vPA^ z+zxg@;H&;2E8rMnPqxSnx`KoIAN4m1+#|3eROHRM-Wp|CB8gd=X(78n`EnB5C#ZA-{XMNvGSU96Qy)F|&LkCA_@SrG zHGqlyJq34S7=qRVq^Oz;Eqr$7h5F<--LgJkWsMVEf~%h>K_4$B5lm7x(~9v387(A6 zc=FwaXiMx(hIBS{WxHK`&E!_JdDS#)&yhD|{lUdcddvQgs{uinbIYC;w=*VOT-J^9 zYbp?OO?m3NVHg%I^Yf7tEn$t`#@Bw;i+j3IBM12;ToXfZO0tWiD~7O-u=XkI$rN(t zp$No^x;Y23Pu>36?2C9|3RDwCYJFU%+cDrZXRxCaHRLY40J=hCj0_qG%dGex^R=CP zQB#7~B=%}^^{)_tf^bD7&uCz(wc z;rE?HZTFMU*>O0n-xJa(EL4Bx(}FF>AR) z!5W#p20svNUXBY9_rAGxA1?lEc(YJ^JDF_J&XQXCtS zTyTGog=-{KozV$*v?nLw{h`I32oVe1K|&kWv9MGXQF6j_XA7XB!iupXf-V+AFH7p3 z%L=!$vbeg;1Io()PSZ9@dlkmunV8vy$~SaP8w3@R!j#l%Sc50+jbO*&5Dz0GIzAqT zKjR*|1$2QLFxtaHue9SlI~R`4j7Xf-fb3~j@nv$>Ex!e+)uco)ww!-84~bZ2$QRWO z_|1YXd&IFnQriy?jZEw9kK_4vLPNuqJOns^4P@)gEg)afpXV7cN>d9NWtPT=HRK@f z{TRf8bHZu#$cvil?9+Qt2(U)C3cv(jj1U&)!keiN2;MAmb63tCYH4zkHV?UISo>IYH** z`<6?iNT=V(kgIb@`CxI?z!dmqu|4HdR%!0EVuiULhG0TnkKWc30Ed)KKs7B9s=~SY zZ=85#h9|@{yTMz8L?-qdf7XXxV&S(ja2_ZgA;!02b>N)4af-QmkI(QD%?KZsm2@t=sUhgRuiC7~4a z8U^80D^uI+e>vvfm+v=teK3s!gM1@d2!hILER=Nv^uvt?K*UC3`N~;Y31u7UD}a9~ zr;hc-QEHl9XIA325mw?hxe=aJG*UO&v~9Urq9&35AY!ZXzAh@$o4PiY3q*Y8{)c)N zjKypWIEQ)06p-W0)v9r+mJi2FQAXily0H@bhx^Torw_icGJPJmT22&( z^%z{dfU)h%Y+`tcL!`xJ)cFSug$7TzRYHC!qQt3iAr-QJxByz$+ijkA&JP1&n?-$} z=+pfD!K=BT*94}pChw7Bw}hm;J48RKA;NxnoXE9Ek02K&rh!Wne=$XOA3ewffGSQ6 ziV=S15<$C52Nf^*FRylIL};=_!3{rGmqvP`%!pG<$rt*FWEgy&r7;Dd&O@bk|1D}# z5e)Zu=PEg16doP_1@u`BGQ~eRkkstK$gChIM1`0C zW>s2Ec!$aP9rkrRr-!Y-q$>vBoz5a-{nw`F=0t2BsqujRTH)^ywb*{uhHBlA`%f4$ zzhzDGr}dPk+`$1=zKne$`rj_6T`Thtu;*hxZe3=XhDsTciqf`THWan?2bz4AQ9%!s5byHh;`*a8iHgH{B#TQ@@V)a*eUBintb90 zE*hm~NFJ9-9|hij<;0FRBEvr4fjW&LO8;!P0II01U7s*&AFr(6S#_y{$Dg@_q>9ZP zGHL2PW9>NI4?BX{2HolNyFC`!poM^c94KKmVqA0~$OI)|^#dWBQvukHgw(el*PtvU zTscD9hO6cSGJ#clROEbUJvLu_2b+pDo?}IN5#KItrnU&Y^D04SlVV=)yoj3|Q);PI zscpJq3s*uE%Myhx)yU)WD?QT@Jj^4$b$b;nrCVC~BlOZweO08eLmYg<{t5w2Bj z=tSA_D1+_-Gd-3+=VT?;wj^(c2mp=p8(0@{%y<4Kr0GXiZ(RvU&+uzmdl7AAW_J-w zmd(X5PGkN2xD99M=Fj(HErJW%C*+085fg#~VSim6_rG5kV$qd6ejxQ15wU~~Qi7Ei zZp-x{2-z~7)Mhp5C?TEMiCnPNiMkFO!iN7jBm1Vgp))7)HDfUg5|ib*|Fx7TF}kX# zYrec0|L*&X(uT`sc`34N>oxP*g>E*h3smF|TiN7#`v@N z(O(;4u(!>UHpl>=0{Tt(D&~8Gbk@Jgelga>c1=s31&!}kCjG+^a|v_V(q(_je?g*X zOEoCirYA44G%G0a9Y=a?BwEuCA5hFX%D<481LhNY)GS0x3iJt}HHEl;SbOk@N3L3Q za166w=D+(%n(ACr8dQsCf!`(q=&cJ0oBEd@M-AauOH%p9(t84@2JcV{cI|f&>miyA zJD>OYyVnt3)e=7mMPBoGsi>4?#l|-Fa^Wc^8lU~Wfkr29DNW2-kr8cEJ7}#Th-Xzr zRIF7IiHJ0mth95Q4xict*Z|YQIlB0R$n92kN<#EvSD?n75eVafjfVco-+>p;q{tJ8 zG@fmh3}LXS&uB+(VEF9)i!zs%mg5}3bUvIS}a1*x|KC7{+48WPv-|Zo>7f-9r*`g1f-Jl>*dR z&;$?|Z&En>>z~G2VwsN#W`Blf!1>hc-*-L!P)K1Fhs&~e0{Oe^@m+Jzt7&3`IlXE( zuB8$r=?B+qWcn}(nl>yo_S$F+;}IEaNL*e%5mYjtLbpL_7V;69YL9NX_RL<4hOu7V#AC986YG6wDixQnoPjXLmRnENiT$;*i$Sn$rZPH1I&IEkDxu%1 zp9uZ|n~MCxgmZJOo}a;fvvw&^(sQq4$_tfsP`G163H9?mQWm^+6=Fe;%cmb=FWxs6 zFtH~=Mg-W?WNPDo#MFXTD)mze9$=GUQDuIrVw)4x)LYW@hd%knABpx!eZ+Wkw@BH( zbGdpWp#ZEo58YB)W|8ygO1sL-zWBY~sMw24wcm)lu7h?>9$L2~YLK~2WFh%m(4dqM{;%lU!{a!ZjkLbIl;p0^5hP}~GV^Rka z;=^DOJ8i2N7|2S|mM)|l>S;=f?RmP@^>Gw9Ex=F4RyeEAe@Gt4G9xq4PaEaf z9Y@DkewsX$lu*99P%v|Pj}Up)d^9jS=~MJ$@!)k{7WY@adi#LR^Yw2pd`5)G!98dF zR(0~>A4orE3^%IHW(pJeLHQn1%+2D~WuA-g*(3DaWo?ZcXppaBX^sRUjs4%tDqy7n3vOkMQXZLmE!HA_=fy zzXdG~jJb8nn?Pi6-;4TXK%P^Lw_UjJT04Ztu+SyJSVvI;j%7-bmDm z`&I{csm;;x-Yq1R`s`6c^XMF+NH*@{-8hX@2Mnx~*F(C&yavGGs(CadryUvfi?Pnr zkaAX&%s2BPVY_Isye1Vcj7syoRUlpXM2c2Z87`o&vwOD#TN?`3EJlc>T(IvDL~^G5 zBvS$obx7lQI7&w$G&${>@52Wl7eSVEy?Y^@f+k0F!!br7(n})V=qJ63KI=ez7x(Al zh17_FU^!?jFm)aEd%Q>e$XursVodgPVFr)6r2y`y(qYS`?vhwI!c*r<2KJP9RGZrp zT&}rMHEH5jVtO!(!YLV2@6;gV_ibxZtboJF9m2yQwNBtue<2kS(`vTm&iK72hU09& zSj4n=Ny2*f2x!RvvwMbjlFYd5x(V*wT(KZy==;V*n#x+=LFrm{?Zu9A54FG$=Fr>h`zZGgDm|&Ad&g$O@TUDl zACo@_F#7l~bVt3UtF z=Q`h_+r@2)@)_zF1UOfKm=>C|u{2Qkb(mN@4B?(8b~kIIVE=v}En4Ga_FiV@(Z^{`FX3Rzb{TmqCp52hI zG6neS=e=J?GZjMC*vvnCI(%fs?1C>ltA<2c++oH-LkcG4W{=9AWLB$@c3)i6SaKTD z(RvZb^nH|uvE+6B&rMrIv)OX|9I8=NgpF%YMu`tN#F(m)2fW;TR5Cu2ii`e}{rc9G zF?p;*&(E2unYZKnRVr!ms}4;*9LoCl{}PE!Z$3~iiorxO1etwr_~F#iu()5zB?pBO z2q+(qvV$!@FsFO0M*ouU<+7Dpf0$uW;G|U^L_O%iwupqsc8T>#7oJ!#qm^7Ouf)A| zr7r`_i61U0V@7GDp=*Nfplxj8TJj_&3^_!}2IK!hO!mludR33WZUf3zaQoMFLgyRq zG2Mz?1Je4uW_by?x~cT8BwB?Ij9Tw^(fMup>ie2FjJ*9^*CLfs7biVBsMC*cqCS@)`y?#Ej^Q zLEMb-&ZSw6Hr6|EkvEjABsberj9}1XDrERZhh&U#?(<{5=DlXnPyTVNgbRD{6UYBW z&}Bw}qe{hHfH+sc`G-5ZtL8@@7cJymcz~8H+Nc>n66ov;KW|aMK$%VD-#rIaz-NkY zR^2tII+&WsX?Xl;q7@*FDaYC;{A4-l#Z!I{aeY1=j)}Ov-mQceMO`@ce9b(X#EqXH z8X3peay0}=jQ?4XucetQ&OE=?d96GZ2es&y3XUVSKx647@u*J#6C^(KWDhXIS;3twEFG6<_*-zzG)l{e7OJ^*NbA~FB zH`W>pQ{x{l29xeYT!vMQot_R%BpL?#emM@B*=nTL7nYGtX_gOv0Xy=@kQ{aq$(orV zJLVD6Xs9LObzO*e_5z{F`^IpnoFDHYb6Hccla1+20T3O#1vv3!lrn--E;rrHV9&sy zAGjuc3s)pQd6%)By^ksXQ)TI(hlsjt6ckww(FJQ*{g+RC-`9*drN=Ac4D`(}pDicS z2_)EQ1KL>lcxTTsU~bejr%8)}4KEpOt7WywmcvLWvqjf7)OV!pO|-<|Rf<3afz>A5 zC(xeEQ8(}ZHe_l)z<)TXsDcwt)2$)#WkCq`xT(|2qaeYd7slcu7T07q6t=&0oIRFK zP8-%%*7)?+b1#uhq%Z7(so|p_digI+Dm)v`(RR5L>WGe~t=LR1H-f^%h;rYue`|`{ zge}fgPx1(_Qy%eL1W?b$#e3M1lWo>E^?18`Y$0?DDUGx_icU1FguyzxY*%cmwyfT$ z!6YeHyGG_avQP35*CW3Eq06uR5qBNyfTyx{HZmuHnH{_cBMtRJ@Z|NaorblGOevM! z#P5wP{D;Ea8gA^nNg6FfA~d9fj_=N!vLAx~lJkX7x&?FOwf{Ll%o6KaCVDx+L|fPi zu+vh>d7**$T-T}8S)G+Us7TsOnqKf)YSGA77>aSM@)pg~^7}w{NA~_=Izm&SuKTg@ zJ>k0d;wD<8GAVp95^i4f`R*h0;0bWNjlk!2%JO}5ZrS|yhtBf&bxf^)&B$?c_b69! z1q14=t%E>+nCBCfX)3NJ>fd{NiGDZiVcvqToPf zNsB2OktnzK5Z1E7WMAC4b-<)AS61-Dj>kTR*otej4ZuR@syN}0vOf+rq zNo>^>-r-m*4fZmGH-Bp#uwwbiJpTh0!zFf@k zpP$m`eDClfmJZTxO!8Esq+8K%nM%ASFl<>vm(8B|&p3QbM&|>n_#!%JqSQ>$S^G6357g^asJ% zox*t0KBQH%YT-i;=W$O18{$~>yu*#BdzQnn#k&rQo0q9q5yW1{7#@@0ER0l3n(fZn zt?Hl|L@nK?F>lnjg9}x8M^HvMKG^r!bjWORPYL5xpC`|hPqWwAs3xoYY%u_|*fwXp zJfT@ePxP~y%Vyw8K`7U+i058OL8-z8=-_GS;?+Wa+)4#Vj4#Cup|5cW=$uC<0?@#$ zTkKZ_X_ZpU)Bs&3DlZ?=?Pu{Yd>K@j`O1q*wIo9(5_Fxa5~3X*NJwR*L>Tb^gC$a#bbPK1^9reyJe z@(xbwBxU<@VyELo;g^LBJUmeNCKPu4NY$E>T^=i?-!fS6c%txZ>!IT2_pWCXRF&Rj z`;qaDDhmp=6$jUDwK6#{54cc&z3$85ql0Jj_FOn>)_ut>xr-0tu`bvbfi^?_8yuOvrHEIdCe*gTae2(I)3xx3TnKVBjsEtU=ZY=GQ z_sOgxhE^M|B4+~Q5+a}-CAxA4p`>iAq==5n54ge)q0|+FO9;PN-$(P58?VgP5g0~x z4zn2cITsl-Skxp9?cd=7L?vpA1*)-;IOd(RD<3IQfbyCi^3Ne8Imr4Mf%2ryqQY_a zX$Tq}bR36kVRP=M9`#HL@|$7Mf?__cWS?-i^gS9&Qkg7W?}VdhaLO|J#rewvMXI0K zziG&1Zo;N_D*F{vpX1Zg2AYiHf8ZGrfbNP!dV4f8bNi(cz?kZw6XryQe`_rKV-h)U zK>)R1;vC6@+$1LFse)EFFQ8!*1QMwFAkkQhhyp<8K~23dbsU&+E4NIU9$a3$<9(cQPcPL zh6N=9*x((ceRZQf#xxP1E>EdD!A}Vmjs5tzr{1*4El7@s|8Twxv*u7T^_cn6{iuwSYRVs3g7t%)09iOTOmjm9?Umc zEQ-xK_-_S!#&!_C=qw?R+TxwJ0*t zkuS``iekmxBf$c?LNfHPGX;Adny!bHl?Yj(o%k$v^fVN*+&=gDKA98Au{16i{@wv= zt7CdPI4xI;`a5POOVb>c)GQPaU5H~^vvw1PfpkwRbf!W+F?kmjF&H5*rXJwfubr4% zX+uOnAO=CXUN3Y_UD!I9>FCAety?^;i_60ydR6tWDo0)43ypJzbS^D0dkuVsF1&M@ zO}&Jz484x{r@M?YW}?gDX4T?K(P-q0$x+fKkvZztVGN`slikzB$?@wKFjA1=MFS_j zT1ghQW5`t$-S)iELh^k~T~_`QMJNPvFHH29CIv|;bp`xskL$cr=(o{SR&jd;2&*RY z+`_@~jteu-IE$mIz8rP$?>g0*F1^~{V^0D_SK&8NpZ5Zjh+1SHaO|~&#osaK0rotI zb)FN|HBkoPh|iF`Oq>adDljP$gJ-hh**MRK`xr83MvUE2W%S=2K06z6wxBD+T*@uH z)%y=!9TP`xp=JC*Ba)RHASWK}G%TZm8OE9H%=n9plGSU%j9l677eItI9h3fNQR%s9 z=5jHps(GD9wJ$8GVuE$SGk>l4e=Hqwszwd4U_7vY$;ZprF%RN7-k@je9Rp8%9IBa8 zP0nThdw_a-$cUK2USiPQU!Xn>Z(+w2T#??jgZ%STOuQbKIqdr z=7SL%Nl|gVw(6Y4gbdFbMo~4oW87p;@Tr=!LIO@I6E?WVE3h74HTrX*5aZ`R2X}Yz z*G?tJciZS=PbpTlj1(IVTqw{ZFuK8*u>+5Ma9bYA2dF8)FozHc5l%D0ZN|Qx^t2)2 zVfmxaFp+361(~(`Z{Httm6Iki-t;rSD~JPjrdH}ij)`9q?%cK3x+dpvsI0^S>p+X5 z#LYuqj(ME=eo7est3GaYi+k-U(7vNMcdC6l=AYhO@_Cac#)et~bj|Kl<$PLGrZm!x z7-lBDok01{-U6VUh-c(Z31Hw%sk6OqZEn(~Ujxn1;NH_t-mvXb1Rje4E0->WCfD4TE(_$3w%UT=Wf(`WCl86<68!i<9 z-{1W!VPG4d60wG(yD89$J>a5nRYRkXik2vlVx>3>4xDQxQ%?9UM?vXNZpZu(2#K#{ zjIL0yOrd?A*QEFVpu{X@ZT$!5e12uDe31Nunsmi+ICTEY8mEIE3+ z18T_h_9@Y?St6|25VIkT2jQpHk<2;nsp;qKl`EvyGnRpS;>YO^sfgmFqA%J~7DSoR zNm^M6In{B7Ku@9bJWSN2zdig4_ANF$K&b>#U?Z5>9X!(hMaVo@Z>|Qr@2QN%UPPc)~s~fj1z@VWqDxGhvaw|DNZ$ zVk-LuE_CMZm-3X%te>VyhM|Xl_oqv~v&gxLiPP}Xi7EaPeo;~&Y@1`;VQ94=rv6GC z+|;Zjt?>9=fQ?29NlY)1Jp#ZtM_LTA#qI@CT?uxoIfI0i4=)}ATNO!^5@+~t+|ndt zLWGSh$FtzR24xkf=7(xgs`gc4h65B|8a_;_y`;jPj%^4*!i(b}a|2XBXhmCMX$T_b zw!d1t!NEYvC@IGQ3QvV*D&`3(2h}%cZ5YULOsHMAQ8W4qiV?7X1AAwwepb8yl2=oS zpt_nFkTOb##}FLw6E|O_(8Xt0n-g$8+$uS`L0D^R`k0AD!Dz5v0GOH&wYo@cz&a$7 zqlx}|>Ou_0JxM9LF+T6bshs>Ito>3z6z-$_se;c_OhUU6V?TL9N_hC@Y_72XyLSJvr|yT20WkBYjN`d{ZO(#Mh%I24ry!7jG9^aBv1KX# z%W7}xwU`(bO`UQ7I|~2vb#p0SlJ>kj74Rfx19O+v6*q7o>4E1je1Yjul)#e_DEbvs z0%|J3kC1&Ja`AzF)-C02uyM`J~5*5tOTuK+5=PrZjB2d3JJqSv|5)pfOr4xWr+xr!09jp0v_vKsQWr2WS|5_S9 z5H=0Kz8;8wU-62>7Lb>1>Jni{4Z0A zAS4)@k>fzCo>~pkPV_%>+{@(troVQ*7pG#tB4td*ynI70f)P7w z6Gw&Dp}%WfR*5O?2NQTXn&n;~9y3eD;di+X+F%P=R2qoc{QQ?Zcd!vcL!}PqyiuES zGD|?{xZ2zna)pW6y#8k_bE5IkYg$lo^@3<`tNc+XY_9cw{4jz2k}r7B@8z^(VGGc6 zyP(>4E}cfRj2Il*Ply>$f!A4}a*k%}`$52v`f49I#I2d<&L@w}uqoioW|^JM&6v%M zk}!7joG@$Ujlx5It&qSpu``R$Io;5N%GpG`Jv6b2WiMqj>h zF~s~?$L{epf|`W{ecCp4_(dUn)CfZA-gSAUEK`O@0t}T9WhX1O3}I8gNu4iau0Nmb z*N8sLb`Ie9SkG3FgM|t3yrDSb^0KiipXu?%9wd;>0-Df8%9HG=5B5qpIO+?+7C7>I zkb4TQNnGCk(M;d2CuD}QV- zU%z?cYc4~-pgX{GgrXm359asDf#;MG^iu%+-rD=$q=ZUE(_TP~jIC^gjpt(PN#CEjDwb z#8fPN>hZrlUdCYUu#qzmHH-lVD2$N%$&>fw=>juB83sz$1anzO|kOJNJHq^>@OWAtr9D?fSIl%*Xz_Nb6JFjtHM? zXP8(y(gf8SGycl;!(yORxDD1OkOXdD>!rr`A8G^spDK3s`pdn!=(mjZ_p{$xzV}u> zWE(dR7Jm^#kc>Pi%pWa~nt>H9vo^fnlFuleVqo*@PFk;z#y23wsEaZ6_(j!}f}74C zpn&2VO~e?_$s~HaU6QJ@Reh#slC}TnNGpG71Pqr&COMV@o6#rQ$O^vDrm8zSZr!FY zUBxsb!&iaOc)^dVP##>jf-rmZHo1=^SP~CH(Qf`p8-YTfZ{4bFF*6O@!4 zRQGIr#1CgvoO_y;t@q{nBdnaKqK!; zHyzkg$5s0Ug)t+or7u11sL#3RBCi?&+6IJ6^E!--$0T5T?Mtq0yw)H983sAF@{KRr1l+SV3KaEej5%0eS*uCjTL%T!OCxB+%zz73$QU(q)Da zkg^0?&~cga{`S82oz^`^?$yIDn5Vi(*7XKXmFrVY4+Y7g4j<|SNQ0=jWg<&(c z6Mi?w`tZLwPl*sGaU$RnsEPd3j{bVHup4zx`+#UcQYh7IKMJ>5X`N>OaqPyK778p6 zP}_Y_l!mIUOg+baL*Ts^35D}ho>LzQhCa4giw!6>f|)!!{dee@-hT46jkR<8 zT;`6Uwn2O-atb~@KKv(-IncAJqWD!LjaG|H_Qn>C>m0mHv;EKd`5=BNM5 zn#Hdv{U}p!U#oOt4)~&zj!mQaJK8zFCcZ_qz29I&3=`z5ArKlc26H`z9#cZ6C{uwC z&LJgmXj>fVi&rV)m+A=`(S8^go_Gl{>=jb@Iv~#;BVBrItK`ncMKlt1v>cTgCPbn{ zyKfrL)sCHxcXwjYR%?`VK%^((yZN5oa(S&o+dMUD6}3j{L3FsgjS+fr3Y zoqpf1-RE$02E5Sg$^TbP(9{(ogS2EsefUIcs1MIX0Ffwkh+lh|J_^|}7ae6pZmZZ3 znJy7b*12}zHkNs*&o&VU+ih4HmAgfmx2x~9uMiXkdrIZU^db8qhSO&yh=5}la4JWP z$!BxPh&9J~{IE>Hz%LZEuo{P_qbm>5oyW|*-uUQF#U<0gw&iozJ^bnlS|Xff2Om28 za*l10(_l~*mPrFKn6mt@ z@eek2i!4F*Buc6ENU}%0DEZWXH*>Lty(zaboRpl*ZWcwUskRRQn8G0uzYrB1h{)WV zK#9YCAvFB~KxK`EVkh&S0#wcIWj%Q}!XgzFH*Y#oWuoN_d5oMG=O^=#YYP{z8TSXp zj%VKn7UTx*WbrT{TH@X90ZE==ts+mBOF|QL|FksOfazAw0^!xh?h^YIuuEu-i&2ZE zo|0zs4R9Z6D$;AG5wix9+=yF($BQZe*&6AEmtF^%)ZOd*)D0EpRAeOpt|;y&$S}ld zu5mudL@OhIo+?f7cV?pYP{<!@Hr zH#uqQ8G;<-{Ge_UG%G67-WpZ3R&psy+Z#WmrX$Dwpuyy=PJ!`W)Tsz_ZGrsLoQ3bX(AN=#DS&IP$s{)gV%{CM(5n*h^k z+ISwQx5%X<^lNik1BdvoryM{8cH%xt|WP9uX8=E^U z;-vjxN$ua< zvJv^oe3SdV+ysua$z>57_<)Kd`>bmw0a)G04sr{==k1q#7lhB*Iv=L}8gtANJqPm{ zTMJ-65Hg4kd%tJdcF6b}Qf#%*>qW?yo!w)P&^F@=>n**{u*LwxYS!zVauNYXX`~ zG~gS8!7$7HbOlfvy=xM+x@%9)^nt7m|B;k>M@x11$z8g5j4{+E+=~!92d=+&`ENM+ z2LB3=vRUfWo5y>=aH`*O$fls(xNYhynSRB{xm}l=bhCd$qun+Cl+Q?^wu=*QjI=#Y z@RyGzhe~^*anMOa;cI^y>^3ViL|0f@*BAk{=$LR-7;zy%gUYldy>&lwj_JZy7QVkve4DUW=)PZl0pZYd@vQ(n?`dnKxj>DRz}Owwcl?+I5U}&L@&L< z6oqY`Q3{s&i*Xozdq{{+)8xy~`%;iIwb+Sr=vX|LPB9)iLDrbiK&`Z;k_d2CW)W`H zTM3aee!0{c#dXD+tbkt8NVU>_sFnnb;0NaaZdb~G6xy!_Er1r(;>K!ugFZ_;G?6xs z?r?twVt&AE`G`MR6TBmtqJ`1D-O-oG?l_g>Wi;wySM=zqLSZ@(uX@SYz)=}_7*Da5J>H@B(< z(e$?IgM1*WNq2$bUhp^+;R@ba5<0}lB3ic^(uzT`f4G=duMN53W>~k%;`&*{dGA%l(uD_3s@q7xalXHP%AFBQT8na-dwf~_7>8med&l>I~!gWyvAGM z)2r7@Uc@DWcrTBim6Dg9e{C;?wz2*&mshl@?Kj7j1w+2dB()WPD3;h54V-S4pz-DA zkDm%iJ)6qxVGcb7l<>(}E*^%BH}$_1@%~3&8LJNjUUb-mAz24H#+rm(@%;}4kIS&m zv=`xO2lnXnQ?jg;ViW}DMFaW_{Y!D@W?nXFri{mG)X3TIAsfpA?llU7yF}>@CPGC$ zSA#g|RZ{1mbx_gbOw>=sB|4I z90kg@Ys!af!!Gs6>6x<{DDFfLoax2-d#z0&eA%l)NTH#lLBzY41XCD-cwul>oi=^L z7Aso}P(z$Y1c$hTRwfc6%RkbR%BsW`yG9?gT&Ah&={>$tX|fo?XxvjVljKUV||+!Yu+9UJGN zxh9MAGdAxuacx!D`e#75ak~$;nWDz!w^YOZunG%e+!30#Tnaq-E3NWCo~tMcw=7o% zY=Kb9u;_CM|5U(BajXxN52Gt_C~wnw3MPqkTwQ9cmZk~LYwLqLvH?0sa5*o!{U7{% zScP&8`c@7gZxo1zu+iB=i|lp!-Zg^0fI+k5ThJ`k@jut#HUHEQP@9&Z-FFDtuh7M&c(jXRMWErOV*wo&+++*NsL>qTSRR z#9_}i**gZ3Af#-jZIJ|&WCY+1A!}#`*0aN$4Z^r^X#Ojfl4DkE+xz5OQ8Ws{S8l%< zo9KJ0FJa<`WQP9Sdwz0DiRrHg19tmtG z+3c>=+(I$WWvf<(>#`CgKhF-OfWbF^2hd|7*g@xJc*$VWTl9^7Br5sFRi)EEM=BWx zP#W=e!;wO4&a+%nqXLfmngP4aPS`6fO06nHxR3tsrotOp?hOAP4Hv98I*9pV#g};$ z8iG3Agtw0>L(-pp0bUU?z<_`=oQ)0f3v+DQdfNLk~V)((y>CTc?G!z!8Ns1Lbe7;$dIjgda4QU*1t5-kPa|KlzY!r^-? zX+!;XcCF>X+Gq-W1y>iKB4zuUG4Gmc4+Z0-STlrOeBVb7d**M{1+;SgU$D~bc*Z06## zzBL5{-DP3OzpFbR%yp#_4QVAG%U)#Xj{Tr56@%J_o`_ZY7W%6Wl!niK_c>cbbpL+= zAr_f#IFz#4D<_JhaQJ_+ybFJU>)ckTgsL9wAe22*Cp5A}f3Q(Pz|Xgs?Fs@vz!^L# zP;OAgHjakJFa}1!K8a)UC~mPm8fJuJL7g|;9oMyNg+}>%k0RRrZ~#w?ifl_Oc3x1C z_7Qo?cXr3}gB_ZSK2S9j*+|r`ee^+>t@jZ7ndu!4OHcK+0VX(9PET-^t*>R{go2&w zMujOQ=+{bWe(YNHNoW&hyqAWeZH~i-y7qj<>_m|3KiVCFtEWAN`G-0S6!;0I#kR1$ zg?D_`t1@TLaHK>QWfq-Y{admqy#I)u7A&<%YFEU#ASAWs)232!hY#q=PzJMEF6$lu z**va)Sws5Y7(BP)t%_;tbp*v}z-n{#C&ZL>nIw_8=A+M>F}Eb3viHa2!EV7RKVD7- zwfT(AQAEN+Rn+e^gQ^aj7)9o2nJTZ@5TAZ6nsb)Z?nH1>@Y%mI`T%w9vIE17qn%>; zdsX52<7B7dcN{PwE=T01Mpi7ylMDBqe?QHXcMLAvcd4Im8WVNx(cy`2pgdFWtQo}> z9c*W&%bPUwbts>B(%x987CkADGGVm2ey!{4lK`GjBhKzljreUxlb1Q&+p5bvB%%I67cxZr(F^}^T ziqc@i9|?=Fyb=BEX^>BtY^8tcp#V2P$iIb6LFPu0vKQ~X4HnUNxt1SpzorS!)EA`@ zPRfIR+u6wb=BRTr*_azT)Sk)k^K*yXZdV5pKfH`1UZLfc@e30uaDr_@Z5sDG;Nr2X z@ma%6ez{+smrXthz<%Ak1ncK?YBY<6$stjW0H{I!^0C6A1R=@r8CveTW+flAl|k<& zn2W}3YHm=6Bsp$B4a_@wf-ktu+49O)>HejsW}oF5KQ`d}NE}n_!M`e2@A^-?#Rf^( zI5&yB^S^RbDZC z+tbgj0|LXXI{}>zHRZH8oC@}0V`C~C(Csgc{uCDuRV<)cQBYRS0C8sg)zMQvXh8L* z9^d`-F#X^LnNF1Q^lKSyZlJ@C^Ngy?DIIxTjgQiBX)s#eH^;aI?s&cbf^HU~N&Gl& z<@aNbg4*=4r~-R?X9(^lW_fvDkECV14;^ls=cQ31AF3@M#z7 zRnKhW>0F9ojSD+G#fq;*23d~6SOo34)~9k`BJ*WOi82c+61(uk)O>$Y+L zYjM7!lKdAi$kUOiKV=Z~?c{!K>(=lyGl4*y0^CqQ0ac-}43%&sG=F1vg3#hWZ0*!` zUp&^nMU(vM%3ptU6ct%isu{GA`j6pbTbOtYM;-fqbgocS z9e43?+4ALrluJ8IuF$(ow(^dGVNS!|eS=w>DpxJ#nrkH;s_m3~N2ndpeQL&>4rl?w zw;lx-3b8mW7bSjeB4&)Gl{vh!Fi-|JxJ!JT^m#dDq!xr56*MRsH-K=^^EQjlt*QAr z)K>Jtxe$oeJMu_kK%*53oVlIG_A`@|XWyirhjP51icptam%SBmeb`a8{s|T_M-(*` z5k9iLib^6Nbk&h29f|ef(BeroMt%6S-l~^oFisP7BINW*Qx+4e{%x@>&*Up&ce>BH zA2d|O?1Yh1kuYS9M_Nd;Dt@F8EMrGooQk~I)IgjNllb_h93eQIcFr_xgWP>hBJhYt zCiFDc!AO<3O^!nz@K*R+ZYzJB4ZK-8GsEMn_^~PUP+SLR?3;pQc&hs@M|A$*#@SnK zQ%&Mq1cnPC#O;2fqqk2r+Bn29`Pip_?gt_z!lit24TZK^hUf_M`ZQTWZ5-uP66n=; zI%5t35}n-tSOsGe_RbX@6QKcXm^?cd-O_(jMw~TKJL?vOTt{^kJ0%1sJrT7ho0i8#w)J`*8L)Sbr91f@>`sAHbHGUZD7Aoyjn*itNM z@@5s#U72ZG%S7vYM1&q}mlRO}sW}Y9yOkT@mS#P6 z({xi)jh95ClNN2ByJ$as*;-+U>DCtS(OxG_GH7Fq*~Pv<++*0nd`m9lEC$eW(W%hd zI%-Ld8{5j@0z!4ChI2?ec)8HBM`TVR)yruowAe^lcAicRe<1V4v?fcN#nOq&6)~AC z5GH=NhidH1F~?7nC=?F4k|xeI-JIA=AhC1p0xFd^ggb}}=>YM#@oi)E(}=*0E^fbk z==gPynj)}D?0-QhL2vOh!;)Uw0*noi0`V8IP@Y??y{M{$d-1zEkP_z*L-Qo@%m`3y5d0r=Wnd4Jn(I&a4>rSk zi2v@J!6R6k7cCJ!+VqQT>JJ>LvnWuejjb8Camt z7iSS~(&fFvT4(ECeA@bd)l4#cX4A9Vrm7*M2CvtT*+!P9G`c=}ef95HcZ#R8N%t9J z`L|_yEz_qny}13ODu8Nm=?nY{9)cptQAWqb35&a6L+2Cwx8gMT`WnH18T$CsnCb+) zyG-;Nc*eB6FNO+Kcs+~#ic>RMV#x)Cr+OYu0D=>wZcdx*nD@YC`3ZLN;bx01m}ZH%9u1sCK}vQMCIoQOKk!#m z7WZpaqswP{_I0ADy`o4LBlzc14lh=>S(i^Ool<@9ne0O03DEPT>>b+5>|8@X)U*{@ znZ+9(CP>yjqKk%|q}1<9rcC|W6Tz{pZ*!DOhQ60%o=idKa)>6hGIC+d*yc*rN|3+v zNGj7&)&uQ(7Hy$+LPTbnyt6|VCuSoPNdkYgv#O-_581}1j+0**U-KU6___JdcEip# zhw?@jf8wcB5HG!O))lvBWwWQB>7t1%2AoGtQRtiNx*UOQhvwWkDoANSOtx>?)mZYL z?)Y(9WT1%AAH85>e6$R%fFc=$JA{jU5>U3`2>F(M;9K_vlT_u&0SYyC=d>^kosuCj zCsU8^CW?{FhP;NrE7leo&k7Ny!~NNKbh8gbq`uVM5!Q=ezAOO(s4rsmsDyxb?Bmn^ zliORh$6+fjra~b0T{J(i;-EOel^?QUu6u1vYyX1|Cgy0a*et{)5YOh20z=MaxV;yc z1&k;Kc?fUK_s6>cbcF{V?_akWEEAg5kyFoM2+t}le-!(YpR0>>3UHqNOkr=OK7>SA z*MkB?3=9?alrGF`5(L%+j45)l;1h?raYL-Xv8DD5$dfpODCND;@UgPpr(xxfJjHg} ztnDTMWaz!72SS)i@Bvj`IjKkTOe<@DZE@3FW%eO>z;3lZ?vrvn`d}rqE!g>uoc~f{l zedt8%IyPWnCWPe}%WusuD4~)#4y)7nUI1)|lf6?-J&eMNF?c&rSaT^sA@ihEGKYao zEB6zrML8jk@$mp!M|^rviineNpWt>|RvwV``{WPZ9j9Y|*w>R}lP^*L9Vf%sS4QSF zYda=O4X$fn4tZGJ8q|4bmNig4Dw+Rgd!;Jw1mrXv1u$s?g7JjJOCUa5*MdL{1U|cj zSKA6#v5v+bL?JJ**mzm|lK1ZHkFMo8xi799rTZ{9o@>dmV6JizLRZXoZ}U_7lSHuyZf;JWPQc27Fmh{U4r;iXfAl6P^cxi_FX7eNQvq z^H~pY$FjI6r$1j$sM*J~F}73%KvOcte^sF}sWzj^$zF^aL--Q*WUW>ZMifY^1XJ~p zGQM>e-s2nRSVhxB0kYa3@Yt-dH=zZV5#PXb2fx z-(E%C4PZjWnGhbnM1Q=TIFwQ8n6javf4!P268p0nQe{DA0F4vn%gD!l5oPmUYlli5Z`#gf6<`_{M)E`Y z6Mc6;_QRJmVNZ@@?{_$&ddY{ji~q)QUbjUC(n21@DN>_!GfqT0KF>Q9vrWyk!v`%< z`mFf=*p<}b^{t*Y0wd@N*2UAIQgPr}l>rByDw&I*Fl$L)?H2Gdh1TTYXxYJE`~@-( zH?&Z8s0*UP{7RbajNE1Yb1wsUbX9D~PsL}^Fb%2yXR{-Knhd)-1y#y|&z7-b!{O9I z%@QL?pLxDoV>Wl^`}x+Vc>G@zhb0*VrG`;zJ&kE3rQ7CL zT^_QMLxJt`I<6!Rq}@4tCt2F0*udhF7Z#pr^+ZO$2m+fr|9*vYU;|F_II{%QN=mun zn?1k0gTXuecG}O$J5s7|x0eu^lS#PvZTg!M*)Gew^s}^c?yB>m z0l<&EK)d6a+xnJQ5dwv}h|Vgai26r?=)UT`2F!=!we+!OnKDo=j#nZ*3MARW92K~> z*Y%!v#lLATCOc`Po=wp4n|57}APhfPK8LLk|3>v>{`BGpVrra54us;vcZk+?Xo41& z3mmUmXTl_p`afofV2k;4iK(f>dr# z{>kHed<=?wrsXfRDj7Ai8TQo%C9!i5n21BEHI$AI`*;0q`N{307+am-&hII6Q zR;Y2xVnv8(dxwvLG`m%~ny@uScIg?H0uNxkF6vV<1&&(>(U1+_#;zkDkeVtpjSWtj zt`I-vlDBg|t_CgDjT&uD!h55uC-A8?Qd(ESNn?dGC!D$U*21oF{nBm@L@mMK+L^xb z0nA!Ix!MbFL>bK~+eGDgMs*n}{n~W; z05dzH`~M)I#3*UbLXjKcF~j3P&u7GkC_J}uUD^`Ylc@L@H2quVE&5DkgI)-5@rbEi zLbm6hNP2~5>(|tpJ$Bu@J1Tq{RqT~r|AOQXhjMrhW>t+3;*sW#=e7jifj|xdv2eU_ zr+9p8AM+t1(r>ZH*VZ%_O^02yWpD~aR{Qn+F(sH{TxX-a-F!aLg;jql-I}9__mkED zw(*(+LbQ8xVmYcG?`I3%lw?g`eC%Xkws&F^lU`XfWv5ARQ{s5IvBazM*3;dMnuM57 zBaT*hA&w=y%1*UAmA47asn>Vlce08K*j$l+#1(A2<92cb%r7aDEoxC@=YprUvmiEu ziLje-Y{hN zmE&Re39o6(V*IhT5ttaqNy`+@mzGgeFpeDT;v0mV@)2WmKc)m6(gJ_Jt@T36!W=-E z^FFEz#;oe$Tct@Wur{cgWN=f_16SUQ8C@4W ze^1UwhnyZ95)zbodmu@8giis_KNK!slp)x%2Q<7v#ISZ2l2&#M($xT-NSPQJWK06Q z7X9Louloo=$Y$NSF8(s9>gthsG%uu#U2A@j%l&kNJv+0@pQSfMlN>F@F+Xpz1tDG= z7n48WGy8^V&*T%t-PkrO8#q*A7K@IkpY_FPz%Q5iSSAWuSg%xUp%aZ+^xd@~|6OU> zlEdQQwD6o|H(xlbZ^n}X*|rMzFhL?ttBAzhjAg_g^QEI;{G{UNI-x|Cs?>!mqgi+b z=FBgIfl+?T@L_g(=zq(AX{j(I%@)hYhxB&;$a}MlVv>QK$6kQDwaT0IoS;3C#^!Oaxw!jVx9kUx$cKsz4c{;%)$>hSN+ zE}bL9T9=8Hz1 zO7kp_o(pw|r)+_Kz@(=UU{=i8G6gx!nv!OmAgj#Du6y{ZiFtF+NdN1179SOQ1_pwH z@%1Mb;?_**e*T-PLwld9fOSfsFb?ARP64U-^@4WB$}H$XQBj|tb*!`&`ocaB_h4Jt+~j;>l_9i~Ib%RP9x3ag#EFF)CK_eSDmutpWns3Z zz=NYaXm(07MyAbx9jpl&PaIpTC-Z#{nstFt;8_wwbX>a(j1P*|^)z)SV3>$O$~C; zEPsvnAftrpUC@3{Y7cqX*MjOB1fZ8?jDor;eF_)!8}*LxQ-=U{OLZ^_xKqCO!n}d; zqsHBhJr}$m&LEA`YP8D-{lQ1BcL@kJ#Y-V`ZI$3GFvqOlFPPnU;UDY5Ud^co`0OXH zk`wGO(U|TIO4C&aoLy+uBbLOI3|cHRfQO_!#7xBUy$p_HS?a9wp$l=vf| z!#<37sW7|C(Gx9oESl<8Nn37xQYP()|H-?&1Jl2AlJY@FY?u>5NwRbQNRw3Wjy`Sb z2B_X7o`$U%v82RfbHU!HL`=$poJ7SBphE1#;*kusF88>FKBG@XEHQ|C5ODNS9EhS! zZZe_p=}o=SiEkt>xTd^tx(WiwRXny`O`G6^TtD|2@>qyi1e3eiBRjgW~s5weI=DK zrb2I=Eo+F#;F;dFxM-Ll86SS${`@~9LUbLHEpqEwHnm!XS8-HXAQo(L=AT{s7KX(}mwo>`=U@>qA5bfL}zCOF~b~baaJs)+b zXe5QRo)5pt{f}Hp?M5|Z~S;#6FS)X4c*_Dt|$&s zNsTR+U$lXEQWM7%BWy8`YNqW8bw6?KS>UDw^wB?VGv|8jiE1LhO?;onY5Sp6f=V^fO z1Z|fX?X$q##emOWo^p;W*&V9mU17nn)5wolXCf>t)+DLgl|(>KZHkH_>DIxWU;L4~ zF?Z;#wyU1i6e<+fX_0IOC(UYx@(m)QXRukKo0m5-q0&wM?=a*#TML(BNJ(~O?IWPT zs*yuO23B20xtA(aA8Q0Mt>cVYLBIW1K7)_c=6+!2JLuZ@ZYR z^1@n37zc#k&rhzLv*aa6zV2#WuuGn_B#I1827+||uCcWiYam&Qa%frv%w43HL%#;<}K zb}j@EBDNc6zqyDRJ6=L%W{-TvHQf#~76fMq^lITQK#oE#@Y2$6lO#pGM*X#eJzTA} zUH$idCq>TLb&S6O(9@iNF(rlww|AL#XC~84qa-p=M=5WGxi03ZVV<^s_NqxS4 zzmKzERu6|6*tXT1=m1C}Vd!xY9H!K?bH9eODq2TF`W3ayoHza$^`cH{#&_?G?s{8+ zGLJDsn<$IYJ*j%$fg!Arg-R*z)u=WlKLnnpqkk;w^mLhlqdyH zNy+v)Co^TkhP?&Qu$c$C81Ec1@)UaA?a_usNSo$Ydu`{u{xs`a;rK=Fo2!L0ug(-p zBNHgSTd&A9blAi|zgt0YT=_MKSR`)fh!e@#q2G63&ewQTX5qEAUj8Ld5s7RVRYkmc zbG0$)Cd+pTw_S^yqR$?oOH9B%aGA>TuDvBJQK<14k}Ht$Rz)0;&iQXcgJ|(6?zK!l z@MrfnWhn65YB=~Uq{Wg(XxMz8g4Yv_`1~l4s*IzPC!II4$J`9ba8sQ6mO6F#q8Vje z!76PN-(N!GUMq8kR&5_!0p&oqsR|pd6Rx|RL_1Dj@rkFFT5q1#b}S?Xy*^G_#XmFAds#gzpI8bksmb|8sY7 zp^{IEIxQW`>TO&LO9tQuVrFu+%kj2{T`MY!^G33ySBy`NNMOodUm>b0SGHh&%hi!Y zkx{ka{kzBOgp{@pR_XiOjT;eDVRhpS9Bs4Cpcejx4e7HoR-C%+_a z7KD>lf{l{bONDGr{s69gDKK6L=&PJJTlE!H>oEGVwLR{&NE((j=iT;VL`5N;bdJ#D z0VlU!!WDnYs$sYmFooVWAnU8lI;og&h8u+xkC-M{HVQUqK)<8&KMkjKVI?m_T6kY^ z7_fxneCOUU)kvOkJ4v zLy+I<4pjv7pH*g{o^~TRz~}?A6kWSd~Zc!i`iMrs`uG@b9NsZ1}1J2gI3z#?-nd!2eSgMS*^dV zWZ(!uzeIWwq)biYObvjg9cPMEUyx36aO*Icif*d5EH( zUq1KDF#I9fpc&11G~~jGWa{$aU>?4bKF5ox&W-5^8Q3Z_(N}d-6VuC;cYI5%t*%PW zpe)LlxVO^t>PA?@l3Q!0jSkV*uH5ni#4{SoEJ1wuvMOo>m`f%h1RL)?g2hX-==-TY zk3Vg{-a?$IJdHV+zOXva{f)OZHi;oX^$eRHToaWmVk@@bi69pf4$2_BSa%Qzkg1Rz za+fp@%k*e(s{<@Rql3qvuu$^fU>j@%O%?~46TBfm&n#~g;uY=Bj!hJ?BTn-wADxhy z6-JJg2w_#}fiND|8xS1ZvYn=iD1Tc47^yy^4X8EplFSs7vrq|X)dENdTCCFx_qL&> z3X9B@QP50Zp0)8v?0p&SkCHr_1NFF4bHkE%!d|p}ut&08-5+!kv1Czyi@>}XR`@}W zNz0vAriFkooqF-pQ7J0O!!#&5zhtV$q)WX5hsE%fs|2TK(5nMsV9I7#<;+-2ViwBQ zHFfL?$wV63T@~AI->3n#5k<+1j_3iK5Y`x|bHJNOS^qCpQWyrFz$ea;_@6|+(-u-L zIfI^iFO2}=U=5ice@WOb;dtgW4dd6BOn0(vt}_=RZh^3(i*=at8o?{$SJ>5G>xsh5 zUfDOIopUbn_{$=5N20gOIlmlP0@{$K>P9zMa(!fHSGMyUx!Q|ikj zb5)DGpcq<*GYrgwX6IyHUBtufJ29^Q{?e^Y1qrm9Se@vc(gyjpx-8qwmRYb5b3~8x zLDf;KK>E$+C5)Qs?RigNp=DJj8yPerTi*CcEa6o_quExr6B7|>7Ya=0k*DA0?;ahevWq~_=0h@sYlP-!0ZNN??I zgVNe z%jx8K_sHBqFPA(-CMD*0P<@h?NyGi=*VCj~K;0hm$+ry>X6kvs(J2|lZ0(xBqQvx|gs&oPU%5ssHP}td<7{wALG#S`3!baQ!zAAIL%$Dl#8^dL^RFtA{KD3|dp?r5pR7fS1G z-M@&LyxIR@Yw8f9+?RX*{L`EcLITr8dxa-$@~;ut@FO_{8cTOcui9_(`c7DsD4{C| zjo1@4FVt*Fpa&*Ov#OSrZMJ<(-E(Y6*}VC8*H^Bt*OIRd$KkU~@PVu%Kg8VT%F<<0 zKzZ&)){21F_0Rn2 z59odI9*b8}{64eqN$JGN@A38MgKoeC(z_SbR3u4>{^I;W)IrA8u7*+Rb`{@agWiGH z+v|lC_O^*=^{c}Nxz4l^LW%_(2|z%#fP-f_0}#EJ#PRIpuJoX2;xrsa`S}GgNZXkR zvBZvBAyulJ`lC&lKwd(Bra7bq%J!K*OGDS;p+>h)^Mv7H0#38Vhh|eIHWv)ub-)p? z4AV0Re~NK_;8ZlfFv+~>%)-F=f&E4dT{NU{-la4whk0=+9^$C6KjLNQj5KCN!;==(abU>y-l9lQj zcpkbG%V=ND%rxY?Wii`;#|sxjI_XB*kaCNN>u!@RLtg}uJ{rVW!nY!6S^EuXzq595 zfnC5BJZ9GTMdzB9)xsX$S;W=c0pX9Aq>`d*qsJUv)iC$^au5!0lTj~3%1jLAZNYrD z&Rz5=av|*_<0nd#JHXbgW@MElwYK(#HPh^xo#O|-=PQiKm(QWtPWd@m4^rUqZh}$0 z^_+!a#yrRKv%-%$xU$^(l{T~IF6P&s_|vGE=}t_5K#h(>y>Z9fve zbk3@k=|Ue`Vt{wkJjUU*GvGMCeRfZSoT-NZVa8c1SEW}oP6kC?zAt`G2<>RNXs*vrEhnB3d`4_Hj>{C*u2FM}}@p4*AUfSI2 z7JD}s0&~9`_A`%ke^UT=ww3n&>nl&mWVS7eN^hSKH0wMG-Dq!Ro}0MqiVc^=y!J9@ zA8;X{BE(EmdZb{JBGFL45_3l=cWtDf>QPwBX+8ntnO(3HvwAP|g{Nnn0uj@S>nl?` zgM`0#BiE^F%^oQOZ<*vgs1?x$I?s)%pz}`7OZF(AtN_f*)xnddWI!Bf__^Fg4I|Gd zaT5_J>b$jE{qtJdV>~UAYcJv))Xx?@az8LUqHlj?8ld*l{Ndq zM?h1?kwWjjRrq5>QTBi;jU!TV4TuBl+e(m%#tshCyRHouNz>@ z>}B@H9l=PKHIkZMRkmljQp32s+*%LByDN8&-WRP7W;iutyB0aKhZ+eGfa7~rqgEx$ zFfc3Zp{xYnRw-vl!BntsRLrMhA1OY*<-PwuBjsvif%t91D*fNx1?Z*;{s8^R%9c$n*uN`~x}a70gd{{+~KtdI$s-<7Lux7$Zq zc)__0+0b|FQMQ|f+uPzWtz_PU6T_a?x=gsIj5KynOdq;`y-XRGmjCZE&NN`Cc?sZzoVbG)OIed)-y z)39}!l)ZG!5i^wlt&{ytdgTa_{y}}D9t+IO=?ug4cxF9F!4@^fGf-S(85LL#YEyfA zHTxWK^@+y3(erjxmZ4!8AhWN+gW?e6S>h`Pj>@U$$poceGRq-cPDTRVuxAa5*6%~^ zNKJWBW-45Cfb!WmM*wD2p@mR_rj}CP0BfzBr1xV$6F`thWZeMm9SV)}b zhg>O6+pe48*HrmvV>?Qo-TxaSlm#6xEqsS4e;c>YZl#szo<}n+Z0GeG@W98jEaG@9 zgG+ajVJ5y&GFnmXfcP08~n7}$Ht8%jU$|_(7p!8;Est6$WC)Q z0P(XO;CdV2pw3f`kFV0nHgT%jxfFEbKLk-pd`6xrGLmAD-es!lE+k-qxlZpO*q-b| zUOWDtqEL(ASE|U^l|NPjrY*l;00h%-IT5Pi-J3eeyDuNQ*>skPvdM~)Z7nDRV(cEp z&I4;OQ9Q45<$LPbOHVq}Pg=Xiz3D5Oq>0R0<82YO9OKsjwZVMiq=AKkI;$+Uqv2Wd zRPZ~^gSt&Ghv~tH|uh zo)%ZJ^T+Y@l|E;@p9D%7;8&ePsSjdU7OHF#XJtSk2q2ot>@2PSdcjTO*S>+SDQRU& zBnlm^M7O^lQpR_3K~4dV+0769u8}5)o{t#s7xw}1pUnlX-jZ#ad$J<{Y)fmcEsy_t z+ZKz$9um{V%vqvKfXB~ogng$uaxEtvf)P$9SZ5$;)Mm8;os_~tBQ3d{ZfhOn-P7;^ zzRwHx^f%%P0i+B^iYyxv3K^V(yf=jF=5!K*l2~(}m$j{k!#NDn(_YVXz>LaN2ty|4 z2H4oBGR!6fn{@bhqjqWKrmJqi=}1#w$wkRYX*RXlt_xYAKl|Fp3p?s`yg{RBmE32C zE33VnM#qO!S$D7R-tq%`Al1)dHCEOQqRkx;j7c{ae(*=L#5f|<6c!`gS5-3VBe}mh z>91qJ(!o{dugu}45+{(`9UpCY8r%Y>J_uR-hu9c{L6^({Y~(tN<7pDpTKpPS_0@)0 zns%Mj(;0;R4oUBu&elCKKq~l@mEn{f^tV}vPB6IQb4WMl(5Af&giQCiB#Tp6c{muE zA)G~yb+;NOg?{qqMb`*+@vE=s0xw)7HIuM&yz!eUhuACHJOixva7Fs#%zKZyXF>My zfp^QNQ4e^;7Fl&xpn-(r5t3Kpvmwqh{SRp2N!~IMPVC!wJxw5uFnuv3$3lZ4LZVm*mhw{`Oxg|(D-{3lE!(e z6?oo5Lvn!H*r<*0zatsdij(icVTY^07Kgd~73e4t9p40;|(NO)d`G;N*#+ss+X7r00QZ#PZ zrPz{m=b8s_UdZTq%T74!Wqw(C;^d6t@@I0&TEOZBcuAznR2byu*p%-s(~JP`+Z*;b z8+mG~Q$MhA^cF$3tG~W2Y|SZ0(%}@P{sJKgmCV?eK5Cjp*M5$POXp~;Qi7w#OQF69 zYx#>)Nxj)m$6+IkJ9NK!D8K?4q|NlhV`H!X8WBXQ4Iv#_BR&AwIc`t`J6$ZwQ>i;s zL-|gU00OsHc={Ow(S_+qb#v^!y*Qwvm9G0;00=uxhOQqMBB4cV)teDAO3eY@Zr`W{ zjw4aG%%&jet$H@Ke80)Z2#%sqe%KC@1iH=BDcmNJyA0#v1UpP;t~FcuGxQ9eS1iHx zwDRz-avvlLNOo>uzUXXu(W>S}upz)YQYsg9Mb+z|ZnZWiS37pUV|*<*G|DL6D9jnt z&BsWEe#ROIrbM!kyv~&u%9Tsc-(!j(1qVdLKYr}q7w40?O7o^K1S$Hu$cx~47i-pI zwNci}caWqn+Q^k3FoKq$=e7cc2~?=Vnueg{Gkh7Hctk zYNOJ~pd3-WC(Cr4cJLagN~6RIaSeAX0vm;_YgzDCSDZk>M9IM<#jipa!Fzj^Qor1$ zs3vFadZLTb=sk;KE-*JteMqSb+(7>-=S}FS#PrCr;!h~=*GQqg^Juu=`=WW#sAb)dww^Pdr_Cu5l5H5-XaV$EitnY((FQeNe2TLXKn`q-kDLqU50XX_ z)wP%!YGT?xfh~Q{o+TLnv{gWGBeq3_!(GKZrF2_7$C>T1hLPjgS^D101+X@!(V;;DYD6xYXz^p~&4b=U z?#{KW@O90lV-EW>x~BHapPwI1ogHw(0Yht5ai2Gcsa zcr{@=@d(giFMF?a<~&Zte=$TTMX$aHcJbRkq|Hn2qC$qU3o6E2uIE>9v)Rl+KtF9hE4%#fi&rs+y~5G@G?hP1E; zQ<{7Xsrq$vCE|10phbvI-_FnU2{M+TM}_TpC@dIN)0{Zbx@C{mGW&ecHJ7zJ5 zQlfcVK5x!=%eQeWW_5%m$Qt07T&vBX2M6_I3#SdHLz~v8H4Y!K-e&lQ%G_UN1p-USI5Dt5&38)qd17EK zG&=MN1fAKJ{wW;WENd+Kct{b5zHS{wIj?Gbq1BP+ceIZJvtN7zu~dLSG^L75NQ@)*O$f3WTSxXq@%F&hEdBiuD;eYMWlT{iA62X!Ja(EJy`@;QH$<^7=rRN*M7 z*Z34wT=T){oF^Q&-MiS6LxczNa_$66ZhY{`9a2R0%S_Qy*Z?Ikp3+9#{qx-R1uMkw zYu-q6#6A=RM>yo78gOPjkPKJ?aWoRKXoT}H=@?CRjWyJC7(D9gmqFiW)$BDI)@?ux!f{XwVwaS_j!f8g$!{H|^G=1oTFhujClJls$JW`aX) ztzffY@t&{i5&GOzTNePgY7o^D=|9_p)UzO@OzPmTDj1W@c}v z&qfwVox#V?i4+@2d>07v_pLF(h;nvlZPpWl9buO5Gvp$P%d_3g;hxDkM4~0H4La}3 zUw2n|xebo>%+;H}hfV7A>~Tb@3{Owl0d_OP$(YMwe%wc`xdW2JpxdT}ZIK)9uq^qH z58|=d6M|R%u|huA4Pc9Ld>9s!jKkjMgN5WnV=~$pqOk4F_~XvwqfM&?$Rip&N)4!z z>M1=97~wX_Rri5j_yi?fjh0cww05t^dA+S4u4AkeTm%A<$(D$ch94Y35i!GKo3#DM zYj-ySxXFEFRHNdP?(auo5tzgvYtm7LFF4Y%anLB`p1W#hFZuf^^}0Nac^IPFJ{Atxt(1D{jIP>W%ut@ngp39e$#$;|zZ3YKH<> z%BIfmzj;?O_+ffUY*F~0)9c=J!kw+<;P^)HJPP)`O2zOD@`MFzul`jnN(blKBFifF zjvtkUyfd8CTx(s-$4|c?gD>M=o*Y})#tHZL7)x}fV6ITkg~*86DhxFj;`|4j{+dw3 z!XNmD%_0}Eu(bICrak%M$7uDAx{Nd8#(|ERQO%^w8Ht=qxeqTeI=xY+zhZJpdwXNi za=2$)t9046F(O3p2(ek**j2U=9=Fq(vT@J zn*M4pHNVZPE{!Djl75f1D?C46kvd{K7qSt+%a+58=2rS&MN>0We6RV$0?$tvK4iyH#ZHYCG()^L%9hi-HO_{s7Sv z^QXVhPngJ(b8D(El_ZzvHd-l}Gu#wREqmz5vF7-#pP6PnRoP5~sN$eH@rmCC=<`#s zFS%L5kBV6@`}yjdyCltZ*J|+mCRi+K;UWV@t&5C2fNpW6&hfPGR817jjUOJb`MhCO z6b)ZDJeGzrSa!g&?tf4;=#IP>=v+~5E+t1`kgN6;}I2y4eLxU_Jf>B zUBB8V8Fvc!StAv>LA}lkMg}EG7wQ5%{B#tC1=018S_m1CXoH&RmVfGmsAdaw@!mI) zKWae}Br8h2Rci0ghw?Dm;J%*PF)E!73%xk&AdW2y#9_bxn&`P` z56vBoMoIX)2G58b@S_Y+5Tzosrxm^b{K(ypl)2w2vrF#-V!pd7b%^lHmJHVX)~k*5 zRNhIzO8)hzw6Cov9UQfq|B)v1YVU5wsGyYnRiMftSCbBY50GOHe{TYxh;BKqC*^zyJ) zEicH|vy(tQsP`=C4HIZVnd1ylvqYO83^@O9SrY=e*F#a`PMx8k^iEF96S>13*zT<*CAoP|r=W8gi;fcm&) zpK+E4gJoU?skJj`3+H@@D7bKE)U{k3sMd`Xe41VT>rLeH^({ogL!Khqnh?VDP*oJN zw|=MJ}Ous7_|(e~z?%CvYu$XR|j69`bd=&FQr4u7oJ7Z}N&k z9Y|}6uvR~LmFb`AC=3a*$=CO4xpu@WA`c2-wQwo?Ie##=|?dNcNS7oYo*>S)|4|{Jg+N z+W>E9?Na%l>sUlMNfWL!-VD&3_?ewC|2*Tsww^HsKF98b(1@vdYQr|bkSCy;o>1lL zOU#d=(W_Y+st-g(evj%&_o94qUjBaL23dYs_5RE$wB6~Dorv9$(#7?_sCpJ`^_cA! zb1-}EBjCR)lheQJ<(+a<%55NPN2tZ1jPWE27*u<4E@Au;_h8Cz2+xTmvHeP{CBzRdnA3B;i2FnKO5_py?371}Y z&vn~)U!7t;VxV^jOpZc59%}aq%TC4S3htKvr%m@1&5fn2GTa8CLhh~UM_aW|`2s6h zM!d~+rAe_;Sn4~wsgeUa@S8THf-Lv1>I2zI0K!shN^bSsaloTu+BJ?PBJIGlOOdJf}7*9yVA&=<9y|lfERj<2Y0lAmGl@YeoQ)+PtE-$#~eIr z)7R;MuL&Cu^qj;t^c&m8SO#>KP@0NiZSr_&D17%m*oa?I(W+=^GFV6OU_zl z<1I)%O)h64SB7BTrf39AKG31FL3l^TTRaYeqa9%9ykyDExE3Os%z$W82tM>t!#FAn zBXW$TD5-Eq@&o7y;4;;~Pisppk#4ujL`iNBOrax}R*K?3ZBhLg-y#OCNl552K6<0z zPrp+T#l^Ew7{L*ULJDM7(Nr$22;bU1i6J7Sis%=~;LVmAE#id+^A)mI?il6D8rS2F0E*bb9j0}NV2EKmmU%5gv9#{xZ*TZ3bhOi3PbU6=%sS@0^~I1UV> z30|nPdwJjobUW!O4)L~ec&%7|QDOS(cIeqJ3_xc?5B~wnRp_-#Uvi;>FId7*H6|yT zRNU+m$H)2eZrxkTEE%Z7J| zYlqv2)Y{@DP0>CF?OMSt1-R=G*;)(E5{df?_)%obeMi7h9-j|r)ulPv5S1GN1V+gj zsdxBrh}PU|SP!IaRH;~wLF?H(_-a@}G(NfwC&1ub0%>fK@tX}#5`2!Qpe*-?WY?p{ zk0U&)VN)Lz1c(D~S9aT#hl=M)T3o-Sm(7Z9;+&jnz5P4V*)uSg7VUYM4V%tPlMyYo ziyn9P1lf+ew8$#Ir>5!y%Ul3;v)da;YY`>o(TAxt8}Lo`ml-1A>G}2(wn|`G1**yZ zP_|< zq?AY6Go>FmyAv40&dXD9|6bB9n$}_e#mZls&lEuGnF>m-=`I=rJPd`hYdwg(`BcCr z%n4(|{$_6$Khz%D?7V0?>y+#&aiV{MJ7J50X}tm%QH#C%h&P4yxMtawNJP{9WqOgs z)8E+!veX08jicp5H!99}i{x+UakabJOFxcq!jZeP+)A|a=oM+)xj#Is{s*nlq)hU}j`pc%2#B~fa_H!pr4 zgP*;PXMFGynJAq$Z(zr14XUm;X0zWViGEqe00F{x(&%;tDKRK)1IEyV@Ay0T**7}$ zA4ZpCK8way8RI9P<_3R9kj&mIn-_mPJ%etpoPkXyq{tm?G$X!dHw*d@RXRYj8L?T% zhc&|~a^VigB^_fU3rad3laqOM#%os>4)9iJ>-mvUGn9dF<@OPeor_Rmi%wU0rky>I zMXdn>9%Je(BJp((7lfxVX*ye)0+K98ho;WQQf zifC!(;1Kx1TQDByhP*5xg^>TYis1#bCoB{KYGhgQ@>mPjt>cia6eM7Z0D(f#lvy1P z8#%My2nW_5di4YX+$5mbt=eq1(a5mfBz$Ds^75e_of0Y@LV;-5{U}~IB|F=2GQn}r zNBWko>H{JLmD2zshF%x;nyjuist@Hmnv5& zj2Qcy0G>|}k$#@+NzZPFJ;Oao2$AiQh1Ul|n#S=I&F1d#1I8Zmqv`>WOl%VEHJK~y zcV?bAGBz2{nxffUo22nCXk1rj(qWiXp5H@*5=S9)nhTQtRIJp zmXu~fUE8oiGV5nnQ#3dG-BJlFpWfRBj47?S(Q@<0$Gi&m8ar0`2J`UG8T7N3cBi|e zOF_@ZK2@|BI(ck3Xb=LWxQ^v9CoiAKl+Wu(s|4?|DVTwsyPcy^6@`wdKsM|f!U`noIa8rT z2!^y~Gc-kXx1BgwE@&a^8-kz@XL#WR0GR2Esmn^gMtDB!xw`B{S(Q`s8$LxVibNc0 z|4&X)2C)}p{CJDAk=fD~<}*cYdbZcBju8bVEalKh3%kW;1Z;9)3%uK}KpJ*8y#v(m zJYOY+C{>7%l|;}GPU#jw&-a)h=L9^d3m zUr>~g)6SIz)Oz?1jA-GiX-?Gb=9fHIfZ6)!ma{RXlqkK*QRnODnQ-UrVN=EvuFSrq4HSFX-e1{h2D| zB#LM#GP~pe(*Ii8Nf`yeLz_2gr%y@P;>cEt>mJe)%#6c+%@^q_6z-l$!S5-(LNu!s zROh<|0tdiCsHlPBEy%pg zy??47d3l6vds4!^+8**s?bOe8;)-zzUa|4v!(W0EehB~L+z?6AsE7%OujknCk^Jmt z{}5K?MWfFmtSq&XiBRF~CWUU@j{JcJAZg7$he^>#=jS7@X*)*)7F#Gq!F^! zWx>(F?xL!sroLttMH|eLiDH}Dk7=2Bb!4K*P%e_TB?75A{U_TwNB*C6+W6l7Q1JT+ z7t3CRZicQrj%G?iAEbS0@8gmae>a%-x517}b0LFEK_@W4`$l(`wppsY-mbJb zlQ%T(I00PUV1BV$ZBVNBF@cVOZP<&GG9Tgr`FW^&Tw%wA5TEtl@{(?UMWA{fFLt@A zwafzYpwL-|6liKzO%?KiyR(wQf!CkhB^L|OBjjPF3O-}DyJL5B4%}SMOX=N$d}x{C zNi&0FVxIZn=Wr3q4GYrV{81q?0t7|x`=I1z;|)-ld0841qebEayHzlH|F}O}{tbo@ z8O5P7nm-_IO~>#X143c|kLuH*XIUCf$N_IwRg}A7@C&LiJy*A%bi|vRCyG#A$RnsM z7vX_=`>y<&`z9d*D}_;1YFq?d_GEN$6&$(;Js&{!=@Af!nlk@Wj0^d!_`wV1EYNMH z_64iCyh?+M=jt31V0$38G(fuHxjeMuHnM#rP{OCWo8qmQzmKDux~Dy5;F1EMz388t z&dN}hIZLkw-CjR=+E=B={<0W+SBO>3ZxQL&+^{FG&0|si`v0dN!kNkAv!}V?7$UdpK4~@r z(84NrWc_}_{8oEOVp3GLlv#XXbuB*Toqo`Z$Ah4H#2q!k>Y1ze1exa}|0(OY{m9XE zGw={Qnq5HP!%psLJI!^ER$2-Qj$ig8i#bp%xyGcRS_s6^YqaW?L6+c0v7En=Vr015 zwqneujCLk4xQ`I68GbM+vZztBoo6J8+p>p{McGWHPjjv{ajHHX4e1&le`9jX<>}Ik z!yxp!O&J&+dxc`dg7ZQM5KI(W(l@7blA(LZPf-`9Rtg3@v%W%Ab7pg3^#o`bED7F+ zlG>3JsrGpvnNi@xpuRUR?|~pV)jFNmpQG$PRXn7BsPD<$xz$|TOd6Dr-l7mbrF=r& zRrQ(-i|n=?WUlf>3=E?(sgV3V5TKeRgfla*Eu|aX^j>^QEAVca(5te|yYIiWnPu0- zx;S1Ou>wMn?00Mbz0MnDbP(LS5%-UQZ1pdo3cKMl;%`ilz4e`n=m5nbpgu7<^{+}K z$18DCW=;x~Nh{aDpMkfDmhC4f?}J#W#jc{Q{GRxGe#eDESPdkKA& zkZmGX`GkHAFqypjs~vJhSBl>7ZDr}_IuN$b`P9)NU>S<5|IOLNw!tBflhR&o$z1b6 zuzdD=NS)m}Nw8>Deqo92w6UFG79%^a&;nGhd|Hg-=}s+ou~8ZW{bj;Hkx=kC#rS5Q zpabplH1GmUr_T?R^ps9sBRpRx!3DtuB5VDroY(J>I}QQft4;q_4v?1zBOI=IpE2` zi$;MTk;+Pyw!5uQqt!Ne}ivi8xlT9sDhWPcSWvwB!}S?^6{g z*vAV`qgDv$ho2T48>rd)1C~i_;jelKg$`fn-Q}jM{MPs}Aaj>#`22W2n7uBCZD2-c zaU}TWEX0JFqdj#K)hA8t_!5|957r8g6S&!4Bn>KGVXvs+*9xyBmH!64&l%TySqitB;X01i7viZP)S7qr_XgCq9Lh`1t&Se|50J4+!RiY$G5C!`=;VRf zDfpt@OKn`+u#rjG7Y%PX_z2I|QH773#-PS7*3RsOsadP}5;{$JE{u#&vB%1fxSKlx zRl5Gh^%igvtJ>`)j)D4m^P~x6a#Nr(QuW&n@BA4BNUXxA$fVLvkaaDuFi1=ozsN40 zGa2sbkOA`4rw!P>^>6Zk?))@S5|mtQ3`L_Q+2s|W6R6MM6Ec3yrju-ruG#T#$Pq)0(2|absW> zvCwwe9lw!sqY5%gMuNj|2BHcZO~|+g+Rv|DbUrn=Y)Uw_{>h`e+=$;ZsN4V)DL;F~ z^wrBHXl)}fcA?B|>vR-~nxwWKME5yU{MnsWMomF>epr|FweoyGY>0fiRp&F?5ZFO)c_Q{kOm?VqAobQR}}M6~hS8x&ivud$vO)un(H z;{WVN_h0WDxxEx~%pdx!jdPQIVN0}Nk?F2O=%8|kgx+Zvs0AFIF00OEs`Hu&-{Sa3 z_cg3QJ+)euI69<<3r3WmlpIU8^L!2h<_F>OE56bM*<=kTJIZ%u+L|I=*HrjI)$|{g zV-`H+m{PG%L^q2S#xERO8Fa>#%tQ~S(p#rq^T9)d<;NuJ-b-^q=`nH-SW0~ly6T(b zCgz~K+qOJ10xSb`kX>sJ-4si@oE-Uwlm1~rIBXy>DP4MKbU{@vB17VdTn)+U$$med z=R{(L4xm6+2U*i3P-TBfn-FOXWYJi*o^BreVA|TmvMhmLR}SC!ub35EJn&=!h@%{f zks>g+o0I?V2Ga|ejB6FxXB9fE)kmUVH~ zHV8AVDWWn(7@iV0f5?SUTq(I`VpW;nS^-ycZ7<-LcGS~yZ;&%o<;>IBh1NapW`Dm) z!Rs=dM$>!_BN0M%Dyp|~;IuV@=a)5H#m@th<_U)9Z-cJMXZ{=jJWK0aNUHh4eCKJ$lq0ZjMS>}6Z5{eQN z#|qWrV7!qo(SNj;4ZB6x6X`U$JPsRu%IF~hH;V2|uj>?fhxe4XZl?WgSoSed-pIU; zQ_$$(v0&~hGh(U2BfRV96~BqxGh2q_u`M zDpj|eclQ;sM8K%@8%-z!@2vAO8i>5YtHr0UAV=H_N{nErp!86>k8ydtYS#ZH2Q>a! zAQhIfGI$EqA4UfptY#$Tc@Sc*`0)r1_T9LdW*ZuOe`M)#>+3}FY`q~_Jb zK!dBk|JaYYK+*?r9_*vj_o6_Zxp_@Hq=0P#js2Dy{y|Fhp)>t0UbG+&lVYYD@Xe9| z?YT;E?{OVsie^z`J4^**uQIFRA?&%_=sNLLh}%b_m_larC!79dLao$8;AAChlN2}h znj%X=U_q8?I7>!cZG>}E=f<8J1Ia?c3W>_JX9BY6bxWlPt*_+)bG5TDT!6I)&tZ~P z=hPzsnO8qiNFB-hakN(svH+UHfx0}gP8pNx1AfxD6rWQ9S`tljfm*8AfHRL!l0Kh`UnV%YP~LGl%P20{WQ#JsD1y#mb{@my zlO$I3*QkR8`lOF_p2{{s6Kab|5%sVdURB;Fh3%LRPkfIH$C+Nv9f<1kdr}qn__w-k z?>@@FgNEAKB=YGfSCP{%h@pm{ed!++e!$}Sv~|t@FoD-Am+2B-dfj@A@2eIT{zeX} zfMg>D-e^!2)(P_niv-(dlLoJy+T**$R1=U4ZGe~^C1+w)XMS;m#U7;GK%yJ`!|})t zFA~iy<8wW+0~<}w8U`~8U=W%dIcfQ$u%P0zZZuY^V8@Mfl_5nSgF@?;9*TP7f2O03b|;InmDM}WtQNgh7yV@Ey+Rp@!RVwERX}d@e?E; zGMBiAHT-#5@x+%lnF9#1jD6j@H2uv&g_sktpinS#OUt)cuwU0I0bX?^1t6X)MBNv; zv5BAKkr(G?@YE;$TgBG%DmEmVKH9$-3Q8@xEdAg9>JexGk5wBcpCFd&!aAC`N@qGE z(|!#=Jz{{w&^8~k^XG(xzP!_B54hA4e_?gz4#k0nPD z4C&`kN=KwB{qo(~&s~T*a<+Z$W&Q)mcgcgiDSoqH_nX_h;XHcH`)5MS+>re#+bsXG zNpBU12K!jLapHVKPC~5%J)9X!OFb$=*@yGN1lbJsz0=&~oj06%?_}BWHlxA-#~)3$ zcwZ7I2V<${DuV-V)^SiTGDjG+d$kH;^a9qhe2rohXl}ySrE^zN5cSv@y2vg~f%L13 zl-4Df3=W^ypguM<+D?4Ypr?ykx8nwTE``)6wy5)>I!sWU%cnQ_ArJA{f*a<8@gK#H5f z@H%==y91c`hfO;fD(AY@df0XD2Z;tu6W+lQzmJvwve(ks*q#C72@(U-f)sL9iUue= z`*>vzkxB&2&h1-wqM_~N(|+Fix@2>Of7(YJZVGKkJ5{{Osj`awaVaBH{?eXc%)48G zBr@N&&If;_!7%>xT{%p$5#zdImz-i@a~DRv^x%wz!wr0Hg-n0s1C7*Q%kn*|CQZq= z)l0lPA&eUIvpMXl04rGP2ECvfIKLEeJ6-QSz6ik#jxzTgx}WO_+>(ZyEym=2U3>% z4qs5@^#ZJb?t;%a?TmmvA$&kFrJ)c=C(5nw`E(@`)%XXx7Xba7R5_2`cb=fa8Vayj zm(U^Tgug*%TOVy#are)`n*A3cM~Ym*m6Gpq>H8y_Ry{z?R+5@n{{@s-6I>j<=qNvr zAO{%k`%p9@dE@rejr8}cQN#Zkl^PzWixq!RXK7;28Vhalh23=QbB#Iznc$y-e6ivo z5bO)rM9ys8HcS4Go8w3@SF?EXvPhn&wJ)Y!TLa?WIuYqo{`a-)`>(afYl| zhSeoL9_$50t@#k>LG94U2K<*g(DX z3_}$%O4H{c_mvxI9(+l~P)be4#s2xnc4d9S_58$r^xP72)IQP(v+iYz zPU~y9i2f_=?_OK6C&}c_XS~-Lw&2~8H=!znoWUjl+#Q?*3~mabF|B?Gc>8jw1pzZP zA?SQ}xoWU? z+V8V23#i;K;le?R-AEkfRxcp-WzX^$)Qf`2giMHfB9yoM$hA%0-8OT#T4Y-5!>O|% z`@0#B>XMT=2}5nBBpK5$`SRdwxzkNEsmr`a5u%c3&e1X-K2S-^#%@jXDpJAWgt-Rb zD_bgshD*{9oH+=RL&*b`W-KpypVkEyySj)$fWQ#M8a`*21yca+vAYT*bL|f5OQ{XY zQo1lj^m^4tWLVuANK9=VGAI(B1Pw=*M!>Kq{X*3PoYn2%_qwAlY-WzvJb(`r z!*Ws*wA3P=XNqyyx`c2<7s;sXlj8V0Tz{lstFffq@#ic#`B=FqSE3)vijUe|n25J_ zI+1&Xhy;m<9P$W-iGoO{anhZ<`AF;1CN8u_rR2#}seo}JSG?DB7I0smI4XDi|EF$x z@DBKzE0cg3BB`Tf99XbOYwu(^2^>r$?R$Fn`jUQficHOq%Z37L;zCg$kXV56K4UT? zF0H_;4(1V#NTr*QV3K9h`zz1=rTc=&~wm7>heQs`MOM zUX24iVb09|EZG%!UXD7iVzf!e$7QBX8p&t>|AR+0zn%`6M2=KIs`h5kqZZu+XWdDL z=56Ed_AU;q4xVZ2KsEs8P)8I>_Qb=Eg*fi!MTSv)Y#b*^56-zc_5C~_@yB}VkytiI z;T?`-EODiY1E6qbtRYD?M0mzr&A z7LoHdvqvOB|KsRo-Q%w#qBwv87V?*&vlQHZW&M)QuS|MucEHkMjA1GnbGn=&vb4YyH{NwGF;2P z>n#f?hzMbJW3RI10@<9kTi>$rSaWJ`4Ss=8NHB)163y5rjsn=E?e|;#f7m}S3dF2x zpL3sDcmg-cI&x>uMjG@}*P3k8eVj7Yn3N5pdHfFi)Z`9~)9T8lfI)Dt7J}{kBy~Y< zC@a#)k^GNt#uTF2Z#>(;!CFlGHx!$ywZ?QvH6dvl>QZnS#N(SZbtF*NeV*tZ^*Bs; zcui$sDJ?yOsGP`$5(C8Vp^O?(LMj?^l!wFOE7CV zxWCQx&w&2uCvxazT48l|+GFo|0kPHbatY_8f$Ua~#Z_CM(*_FEBHS8he+i-k_jXdSL=}R-QOG05S-Np5PUxHmyBxC-(RhVnOs}NmV1r((`xAcg5k5RaZU(XAuSIvPDI8n z)?OJ#^^JyLHXsbHz#zo1lhLP>|9stgWhP@)5P__0!N0+!EX-~_PA%XHv>M2bS}@RyG&JOXo6+s-;{LcE0@(2klhh}-kr z)r4Xcg4wD6mn(L$Ts^6huT#zx*{vkx$0%WQ)ms;@QBmLLCgX&S4Tv-qf~2Ri4L=0YiG;tI;p_S?YULc@(k z?Y5&^;GHHLB*0BXQefc{Easne)uU!u(Nc>Hs>NoL@pR5H@?Bul4 zqri}|SGQWm7#B|!6BuWeP0vsBFZWuZPH6ootRRdnTlSMTY# z)NjadhURvO2$!*q0sGN#m%jgtjQu=JXew!8S& zL3QEFs6EkYjR}-8pY2IJ3fo8PaPH2sW)HByAfG1?1FO@?JOM-Ss478TWeeS_e#I85 zwe5{p7|+{xaj#4Kp&tNnv=WaDAibC(7BX^b3plf8?vQ{j9SnCP*i{{?hy9itPYvR< zTjGqmJi>gRCp#6h%+*x9IHP9``6zwro2YTfeIitTOW@OA0HZ%p5NO_&=LS4i_=h)& z$FleFr_`}#i-|d@gnp=l1)%aOW){7cn;Vr4RT0Zd46O#n3Q0`rLB0b+0jUpDJ7Kwti0Ey zMC$j)jg?l5K@6~DYVd}D2aN;0$ykA?IBbmBJx=m`Xj_&bin|dIsz@B!_v1pL#1$+Fa=D z@WFt zP9tXZ%)0~D9)Cg}4qN-0tfOyc3e^0O@K8uJD$@5g&*hbieL(Kuluvs+Tlq1R4g^?m zUexup^~A%sU@VPIt;`9>8)ct#HmHhwL_Wz9%Q?d{QnUDzqzmlqRzo0s4z0M9AT^=? zu#UKH9=X`rUx8Yvvu&w%vwWS6l3*>@rhR&_#GTC~X-fmiEvf$q8ivIR5){32@9qNe zI%G!jCa>(JoN5i%>FJVYSvHMdig0ZjH*%plc|hQ3IZs$`Mt8T^;;_laPE1%4m?{-= z1nv^#kDSwKhCbbD_u(XH5fSMElerU_@+i=wwIh+AzHGLO2}_G$DWw#Glekc;MbVf^ z9%!5V&pJmp%g(OVe^n65aTJxqb+bRz7GBO@B5)7`5b_y!4bz|S%pO9>ZiE@ou@51r zohJ+fllC`D+vqV!K!eBtK(v?g%zK}!Y%$zp!F*o&#W=el7b=1+RVZuURiuX;XM7O* zT*A8dy)2*tR5JgU6}R%Fq~O;1-D;J~tqHl!NFZCYVIrq&0_lSIekj9IgtkILXq||A zNky!v)8Z^lD;BYiob`Kns{ia6FJOm}9{OyFJa*>*{Gt|*0+U|vV|f_k!bS0U5gVo` zsxh+u5x?XwmP;T$ zeTm|jMzVsJ2D2IC;t~t%pHyB5pIe@>0Jy4)kdBgdCQ-z>_uSbGwlGsG;FQMejRDh> zDrWTQ_yE`T?ncEe-pr!_Kz^x`SXTABJC!o_`A|GTS_vzHpxZ!_E>1t_`{pYp?)O>< z524gM^}S?F8rP&13y8*!UD=H4mx_CD40x@`|q;pE#hC0h_n zYLGz@$&TjY`@UoiIB`UFIs<2}1ztx3DV!nEV28T_r^*7;LF%*M+qsi{PdOF=^Hcz9 zSd-a%!}Oh1LtOhE&#t&mcCJY@#BbL3G~OY<&YY0IRTsZS?VyVd3;w{fOW+GxW5;)0yp@%IdHGckN|*LG+AUTM=MX&5^NavYKl8#B z%FEJC!2?m>@s=Q|HIX!BH=wexey$s&88}G$u=BJoioyPf?3l~~4kczi21zLf8J;XN zLhc5nDSCLwxb5M0RNH5NIMJKkoJAS42$bj$AAByU*CU!jYdK@PpD5OX+%<&^C4f*7 z0~gOAkp%I{lm{|wiDsB&cEHEC6wN_PB6#+?X~K6`TK$WO#cqi z6d>s1+-YFV7j1zlD)d7T`g!tS41}9#W8ZgwhyPE?f_H1n&k;1H`fcVB4)uv9(`1uu9Z{wZ@-g;+&DYLR$Yy@9djdYa+ll>PItK^3#*g;D>92B{ZtRk zRYBoL3A2^v?R*Gpp~M8je=?C%ve8bq}OgUgv6RxUt`{J0aeW+ zQA$B75HdmPD1!{0@5f_y&DI_#hg{}czf-4-J+*SB?pqD=^i@jo2Jxri!JP?fb$`=o zbPSOF0%H3vC?=*Y7)|~Z{PgULt;_DI%Jvv2=`eq54GX;j;b(|)MOqE4zQStBHQQP< zinrXA->kc_4ANAPjU^caUpYN#vr>s6LIK0v?| z$Kit`7QOtdSwg5)FI%XaxSPaEO?>$M^3@{FhTG3HD9xx5wb(cRfZJEsH6qRxiTdg# zJHt{O4VP&=nyb zPF zvqX7yuQy4jKTUZIV;G@2j+ZwU0`hQS-6`#@XD?kxkL0pX3@uxOTS$REP|q%~&?fE> zbl*`j_U#lWta1b! zTu<;)xkY^-h;WC?&{dqMP`&2qLYzYp{{v0f`kkn7{6TeeSmF` zAQ_c9tJ~HV4U)%lZEkLwh|!06oz%yM74U6ODMha83$iJ)gLVIlQ@Y05e$E1cEpf~O zgC>@s9p=^wtz3f@t5dO`d07?P@L_8luYJqal#*F>DE~$ zt+HcX+`6F$3^x!-&>)V+uL&Y`8C?9kk+T-^Z#W-BMsQ>pKUGe)Ud8h;U->$G7W)(e z7C&EI{zt~n_1iYJ0*WKt9CGyC9(3k!9msZ@@N@H+op(STRC4KheuM**d24w{0`trk z5F{whP$<9Mc1JBFODO)ojM;R|j|bVj`MrDqQBVXrw{97D94Bdz4tg*on})1Uax5gE3}acNUG zzgeOWd=3?kM1XreMj$uvazcZdr7^f@yez;=<-<0WMtW&VqGq^P+@rXiS{k3Ssp^ZK z{kPE%)!!ubn765eM+%^q6AxxgB&l%LCH2Qgu3rrG+@`?VRyZMUmq2Qn4Rgz&PX?Cf zG3D&%*;J%eO2c+AC}}o|jUEF!P7&o!J&V-2U>UHfBo07@-MOZPZwJ~^b=%KUC~BC) zdMVF>$~>7Xk?EY1MYnlPD!~Z{kJ=e7(f~T`LL46+UL>p9JCdPiIN{!Ze#NmKGVJD; z^_CY^#cVrBo;x%Ed5!v71n^D8x2s}N9sRpO)p@1E6zRQ!ZJNTXAUEMz0A;e@q z;;7upW#C-I_zr~3{+lBHUYFqtw*k^vejb&HY7C|d<511oMqw2M9Ot-uk#>NKhG8=_ ze*4Pr3(Hqf-w`*sqgq>*OJ^}oBbg=H<*4);y#7=Dd3ewXY>?9WLe2@{j!$7K67@u` zi_V?hIwKWIy&Z>bPJ)?uV5!1;G#OJkiRX~-{bU< z1Wja+)J|e(FuLiUk-5lq*IYFouyKTv(4S8H-Nh?9=<=14Ftd5LDY9X@5&btom4MmR zZnoH10J{?3g@B~UH8iLUFTYZ0SBYL}*Cqt&6qQobXw_+>3a_@4Ec*@ap$pfG+Qd22 zBPSr#z2?m~G0;X?4*RfrMoo)rwcC85ya@;4lw+bqGJTWhhF=ELR4oT!+%dh2KV>BW z;DpwHVwkB?nmcn3?WI=1(NwTtLqYpn$sQQKEZk8C6v!uF%<7hsqLGX*D>*waO*uP8 zAX7jf7&&}b^u@29J3Hm`x4wy+_s%xbwf)1OAcJ3yX4#}jxXV-1HVHe>Kw<1Rxb-r{7}a*3N; zdwig<^hy3&xNwC|__qvkty=b|ia?zX=)^30Y1MANYTBxVS;>t~3^xlvGBkvuZVm&C zN&N?d%^BkH8sDHZ@wjy&1SZ7&6FSP_+`KGQzE=>Hh@3VApR^mLc@Qz-HY;VMDW%x5 zn-eJ!mjJfDFgwy|Q-<0i;g_&N$F9#P!1>zwg%o;^Nz`tro;l&4bkm1Y#m;kRb`H@! z(IRJmbrsTp(x>dubm(On9+JI7@v^;qtGzv}Z@f2&FxdJ*(=wAf&!=Zn>(XOe!-TI@ z*B{eNddi^JN)vx3cIB3se2f7+Eq z=zVi>GiLYqS4=ZD1udXzH*UTJxFz%RYD+GzAn z{GsQqkD$xGIF}3o^X}R?Y3aIdo{aLg{M4Wh!fk*VNjD5Z=_?p1??l*w=WFW0bz@%@ zpaK;nokj{tRFnu6!-M&a^$q4?N@}r5)5qJsXqCK_v}C}jq&Bc*!O_SNZ(@7of;po7 z0YgqXAB(OS1>ln)AprhAKizyT%$+7rE~3ZncutR^WbZGvO_|4y-=)w^Tag5mG*2Bg z#NYu_rag3IDfQa7HG<$#OM0@rsH~B!5)^eSd4yg7Oq%vbuy=1ZqoVwiKhBLpc~g5L z4Z$8TrB#v(#@LR~^#&hVUQeRNnNE)h5_xHN7_6{9;9ZC4wPYD-)|aTY-&Pknz46~UKUMf0BT zsklQlBDqy&owHJJ5Ehm_DAMcL?dCj!yZ}}B-iNZ}DM8l&36s!28jqd5?rv`} zn5)aPgUP>$Q;GwX$>u3~JKFf&4mPD95^t~|<9CvdJS7;q<92MAO^$=teRz^qRS})n zl4MvQhlGjM*L;f8vTQ_w+svGEhPtkvx)Uy&*&L z>6F|JrGW0bRRfrpWl8_m{yR$uHh=1QN^VQ)V(Gb$(037;NiI(3nhFhDXjMjCDcW? z1=0hjdoq8b@hZ$zc({EsjT2i(p2Rg6qBfb2<<01C=^wD~w*Lb@?enNH=jXdV`#%27 zi5#vCAZDYy3`w@7t64ksx{JZ-0+^*OYa>d3&PFQK)oF6ldvd!CE84{SuP;dsZwf(& z=ET%;vd0625`i4mNQotAE`9_e(}5gCdJ^gs#@ce>A|k%6VK8+JAs_M6hCZnu`@HbI z9AZIgdSgu!1@#OXZpKn2-N#>?&XR&Ca1AU%3H>cBBHpCB*p6G)MoRXz(f}(!)W0D} zt`=T11rN<@n9EvkU{dV+yXlH&3Z&VP>^GV>+=8T=iM4Qg>Iv0vtptSl7a|W7+oBp1 z`mttkJr%}xTN%i(r?()2M3bG^!P3FsZEhWHZxYz!YTC$~R?}RxM z{h9*J0T8VaE(sn)ynH^aMQ&1A%$@wnWv{FSdz1^PisfCc?xL~%2-ey_e? z2Cl%AX@SYs>zgO9nV~b4#Y?PYsKv^q&DpHDYvMnWM9$x3VOVr#+07a_g16R-r)n{5*Z{qqXxC>M>tfW-YjXtP`(kI}lFDlY+7HA@n zr90aF;uAETxkCT+LLTc#ytSG6(li5H^5<(5Eu64e1AT73aN#N#%44Q>DL%n%Ma#u= zxO}T0ks*RiRf^Cx9+;PkpykpHmN7Rm`k5M{ zTV8@fz1JiKyWd+}BWs%T1;SiiPch}1*NWu)`&xxP912^oAH3tSp@?{^ks>>|uItXM z;{oZ_9b{5XARTk8)C9{eiZ?aw8IUI@*D>`1KbH1U&K; z1>M$&0Ok)SLT!l>6wlpH-HMixBSy~svhNs`4>f8Fg+t~|^!m;K=1`a6L&X}j@=P6QBn-UVR zhTb)hkVqL`>R!67-@}T@VJ2 zMNe!6pK{nR(uJsX`Txww?R3{(WP=eG-yN>7ar?<7)P=GFBUq=K zU~C{~%gws_$1W3oyLUGqvA*icLoC{Xkf|g$J?>K0s_$PAC43C7O3oHHtjKh`=YCZKXBW`vP&K2O-qEyV`et@^zeGtTRl!SP7XR>A@xKh@_W z;_oj=VFz*`GlOv3#&#O5fQjcVv$Yb!i1({^4}%UxTev38uebQqr0A9}^a6TgiI$8p z=Y1DhjS(GfMv7vRpra4~L?Mek;({(u<9kFuM8+B#ycaP4^5j7d;qlUxbHYivghHK# zNaC`OhTca!{eLvJUDmq7yZ$Xe^G6vS7+QU4hIzr~sXM_@qZG(R6OBraq zqi?;V5}J@bx^9g{HiapU3Uy_jQ7MmtChR3Ci!QCXD#5`WtnHNp@ztY>+J=m48MLv; zUq1PNO7v{vosvp<76BN~nz1=_NIWGxNxdPreDO3T?MDu)a<#7gg%L&*`UMf{8zl-` zl^$_0O|T5aQQ6=oB|y~YDuWKDHb>}|;a0|oWrAO%3*IB#oG!SA`+~aW!3ur*#X1;D z+jTWqba+BuQwFx%@kvt<)E<@-fWmqX6!l7#>#t2-kN8(dD^1jCn z%mXRthcr`F4;e++wC$_i=U}7}JaKiZHGMhp{xc$5Au9pE=>8 z;wZ!QAAY@gLgD-Hkoaln6+z3U&DBeY{v0n$2vGYt=DZ-Z6(yj}{?vpNzBd%dWz~W~ z2)73LxsZ+kFEKQ+Fp`J_PScu?)<>dq{0{XIvTFb>M3qLtN$D_1wvt#-WU0Dh;Ehg* zMgO80Nv)Z3UaCoRz1Q)-18zybs4}~~ImY_dSw!|jGcEv@kv>Rih`uh-jp6B{NwGFu zMX}-_@|l*U^5r*rVc`gqYn4TAe23I*TH5ALW-kUr|0O!xo9wjoHax76TM7l6y3?m2-lPUlh9O7 z<4uRyztU_Tf#AwFWF2fJQ+{@S{MR?!SPGsJ(NQ9LFI=VP&G^Q4XGv22ca%J!ZJkWv z>~xzYUv+$M7gY0S*(U4+%)8$GDy5uTn&rH4r)Z99b`KdP6>f zpd($~JhiXLG**T%B>I@(N%dh@O4h6U(;a@8eL8?*cndy^ilfbCMrt+$ag6y>k-%yl z%EZXJ3TfV7=*4ox`XIpF`%Lx7;N!4ikRXK>d_&C;dP_$|p##kZHF%sDO=qXvtzLU3 zS)dP5((GL!52c@%~Z{#A+aT<`xdJ5PE941 z2N^DIAb{U}62-u!{F;8DF^w_8blPf}{a5xo(jdkW++hlC%_?0uUn3Lcmo3|L3=qm2Y=m_|cR*#jmY>3x*`k?Z+iI zDegYN`xXzFKyGVI-Ri*~jFIFJT0%|n`>zc*%vqrtQ^=#sQw%j@ihPcPn2kWhzj84z zqypJsZgeAI=ofSZ{5Dl0TGMuUE}+DBYX8m&=0-LLnkq_|0x!LlsY+fs<<88@lzs$hckvRJr&>u8^tVo?yR< z#TdW58L$IUyEW$nbyNa^bG#WImgy>|Ov*QF>g&;Izg+`#Z9%T#)(`POlld%TFY|Z| zK-dYJ=NI?+rY>q%$*ij*ufBXb5vpBHeeoCSczppiwH>#xS%Lm(tjG3HGM`pj}46F;D@HH!`e2_7Zc1m$&*K+yeQ<_))$|>l!4FTH-#0KLLupo+6OXgCyR3RqeShrw$wE zGhs6cyz_jR^`crEe+J`nr;Dy8J=KmczDU*u3S4xCOy4;mg8E?V|6wUo$r3a4ca$^S zVm2Lv8nay2nr`2_)yf|;$}iQ@G<3r=z@!}{Aa$HdpUSP@A{yh*1Nj#=CAHPplM|`~ zg=+a=mW%mslc)kT+eh;+-(jU>Jjsi?!tq@mg>n`r#`+^=8=lhn72&&GpIob$Oh+VrX*rV71Y(_u$=QEQDzv*Bq-Zqx956AT?|{y@0fo+9!%Pa+ zpw%j`?cjyc*ZrWWZ)LmQGo~s!9@es+QIy3;Q=TH*v8=)o6ekI%|bEwb65k%t` z4#Pna)I85TRzC0kbY7E?{KFBdszKPUj1QjD3nub1<;kXyU=t4eBYufTD_ z2@9$pLq{mujkCAm7o{1@lo`gPV!@J%` zq;2XBKe%w0dh1UXC!$bM8v>q|@Q8!C-G&|$uZBEkD%uv)EAba3#pg}t))($ht?o>V zFGGxsmTGA#MT8Km-NAxGGT3bQyyX7E&^?2}Ni@!=PVeAEU?)+QH5u^ye zL9k86?-HF$RPErCf~v7a2p*OkmpBp*ZfRmWAqaxb15wmL8NQ6w>D3pW z1Pna3|29n44sdOA4!tPBPqmY}5LSs}vq$}mIRI+J_Gx^-O0NrD=e+=(`iF4W2K-i> z5a{RBewpFmr*K!z3Fyl4l5+$lSuF}S*sZjA;W+huio-|=vsqP`BPI&=o7E$)0Ctqr znZ#5xv-23@L?e2*1P+ALupHN$6>Y6L$;?xKF&q(L_)p#~vO+V5NSFNJI;yv$ETwYm zm!((%__jIQ%`XETG~$494=2+ZS^XHd(d(C(k*uY$QWZLGI}r{wp8^&n$|zU(Hniq! z^Sf7$V_VliL1Uy_xz?o7-s_?krO2|KG8vc(r|!<^<;+XexxMJDLa~J*-z#022?4sg z4l8{Uv+br?0Z|d25C%nSoV!$ z+s8eOk^!syh=|G5BU>x7tG26CCvyywFkvGU6EC5f@+30sCvP+NFJ={?2L=-&aWhk% z9v|HtrdQ&d5x2c6Zco)F1N0lQWL$*WRoRN<0P8y84cv=xH02klyISOdJ>u(~MC9^B zZwx(1UydR<@hsDW1XoiT!uK4{-p>Eoib8A@+L9+L~gurR$kb~#UQRy6W5j)4S#qG5z9D;iZVuM{LhX(z-lj%^>Ef;YoIFO@n z+^NHp`jKlYqHb;yRHf1mzXvQQxH;ZDsC_*#p*uNJ{V$WKND#bm>ZG7#?dXRqcz0v* zzGfGBd<^}Ma-yQ@?BSo%VTb~3pf;S8boWX4`iY76Dmxc}G}MA?o+T@WKMB_tuiN0b8qE9fO}Jv7>B;?JaX0V7P(093hqNEEPs@WxTg-@5*GEi-K}^tx|0 z$%st8T3JH{OXtMp>lTF~7Z_$|=kM;wKKQC#7C4c|H0VgRhtsSA6Tgmg24Qy);`G zLa8@OHPVI7tOnzW2}o5+J}SpXYptNtED@V{%9M8eRySPeh7mbWdB3v4VV_%&@TzpV zhxTH7@!PuJRzH$U^=@zzKMORuezLI#*X|0albC{Facr$IBuLEoC5Y=ALxEcF0}M!T zdFHD{TwnRfx~qPu@FO{cvJ?cve` zExMEKZo&xW*$5ioQlzeTGF6Yy%Cf|GH(RMAxsTaFpp?IkT=XX-B3-5W7>({rAk7s9?PNJkCw|{@~+de)2m3?nwMv6297-ZL?_KEz{bxL^ovA_X6&NI;Eytk;z7{&AIt@- zMbbavj4sKIVB~*l_k*`?mx3bW*acoRTW_vkz5|G6X~Y`LXnOydQKDKsW1q8mlK=Q% z(0m-MspC>RAmJ*1hka55DSZ{=Ln@3%xe|ErjdTPsV67Fy`0n$-XZ2kJMC;i=2H(C` zd5Sj9)JcBEgeQTeRrl5K_s zhgCy5;8_>5C3kzD&o zUa%**RwziBeE5;vaZ2~e)=k(Plqj15BWvpr|A1}cA44?XO_gRB5sv9XP{=qrErB9- z2D41?ihW*eLZIK1)N-~O9kAjfwi|xq9^l`j$&-$0Q_4N* zM9e*8YCR#&RQlhQt%050ga}C3i5CnV-v%*jMyB|s0n9G%_O46PNMHUY6o7+BgW~;o z{%DEKW}4XHkA2}`g<#S!983?~&`pOhcP_I}d2{Jl+?A5#CQfb&s6DQofhj_+L&2#x zlkmtGQw3R-93a%qS6VR-vZrY-1j!{tSAHt=OA_f_b|$qxq`5-gwInw&T??ACSCVrm zoXWu(inOg6aWlJua-iT>n?kWT_oO8=C7W4A0hl{i!mZtRkB^UQ&R$N52i^oESk=&? z-fF|LQTZp*)ROOH0tz0S@MJSIoGUs)${^orm#x-`z@I@O!GK8l(}Buujp%l3U91gH z&}GU&O7J_9Ic7NYOM?mifw2OYDdi20pZHTcLyya5p>F&P3H&;`b6*Yxw~bs^zI97v-b$Vv0jC8#?jJ$ zp}t*q>2n8mV?Kge;IpqfC9qFY;|eejd2vGmBU94Vm5>X~1F(sa>*M!~{d@_x<(>C) z4EOP>x`+l31iO#}dmJRFgC+AfOz4e$RAelUpzXDD;4k6v+08&a62)Kl6TXW9`gy+v zc_T#3D7P;+_yLE{Qoj^3PC#mVImO`UK`s4=0eP^U%n8rnZs!>-m>@EQ<`>2Ry~>DD zMi`a@a~qnflgStc-I%HsNw1wWp8T<&?TzkVBBHub;Az(*{H^Hs?$>6eMPz~>qNHCN z$W+siaV&9ng7)jRA=0GOhLpQ=@m@%fQE+_*mW@Q(|oHO)&jQkw7d+3RZ3b zNAO4_n<57`s^|LPZKZ0-Du~2JkC&|Z&fbw7>`-Z7U2yOTA!AM3)K>);t?ER?vLx0y zd86b?MoAOLNgY9)_mSG#Q@KvbBVPy(%a8l-6iXF)MBv30BkZ$tUP-o`b5_Ut`{`tdQ-z6kV$PU--A z2Y|I$zJo^_S65_Qu0A)Bs9@~HX&g~z&pfhjw-56Ss9Y8g??PAE-dK!fzy%v_Z9`4& z>d3|zH?=5{M{KVipCh6nv`Xx(OE3E5Bgv?~+~r*^QPry-_KGoSOOax+&V3g$Ea8m_ z&;8e~?U*?3jEu~%_4?0Ep1yOT0!-O&UqoGCUg<*mC?j4!$xH?M&m2Y`JuC3?z}+kX zplfxg+{XPBMjQ?2gnlpn$ILA`J<;K4AzG5v!c|M#diXx|f**LEgbR)QsHHs_?Q1wW zA?QFCR+&;CYB$x}_Pf>SMwrOZl%#^ZwN(+@QoMSUGJYT_i3b=De<8ZL-Pu(!Yv_*% zGWImVRG4NQD9l7-o)wDB0~kNH7j=Y*Ub-z0f*YTqEM1%a9NyDGoSBXws+^Bb zGF4kX;nLwTzXI38-Oh@i>0-aRgHnBsF^jR9KmF^|Z*--=e!AmyRnoiG=adBGladmp z)3~_cjGW!MnBZP;Y;ABm%kiatKM+dEU>+0o8k>wNPy*#lBKOwmN%GL=ME`6p7O?F8 zIGwgVxN8-1xrM+IiUuoI z00WSZ+3AAQNHQQS$+VZ|YT-x`zv*%?Vxe?YeZ_zR`#J|wqrca-j0 zO-2dqNS)cFHur+IxdOLYHkRw1$;`IXbTI22EAp(!#KQEn5Dma#l>1a(?zDOGMW3=J|?er@YxxReB>O zA!f)&nnJB0LzMB&bu|j)cc|B85GY_=;}AU&F9V2aZ^p!$hs*RxQ<;2`Kr}XKo~+% zPzfniiFqBP(g!~-9nBa>*G4YETSnPS=hy&TOf@F!+Kz6dRy2VBl3F>h;DD|#4owy$ z>kK9v(|D|#qM49Q+Lz4NM7*%C4F0dX%p))MEdWrfz}AkI=oEeUbS6|p0inz?VgJbe zJg-z~9(ko?p`!k)XSxd^k;X9Y#g#eNe7Cy}a-Pkix`>HDH5uDR#`egndD3CCnn!w&p%ED+_yh5dvoH*1?%t49kuTk`2ZM8|&Nk%mYmu*&rWpZ$sH+1C`Y z@6nnZIu!yK6)My>Q&nGpu*UvTwd8>U%?;=#|Ic9&0!#i3joA4F2rBAcuH&q)5y(1E zE`^piBOSr_+m4-e;8yh1t0QoN7O$~eKj?BEMzCrPwRwRc!12ydX^aBU$Cc`-Ng>m? z`vNjNh^T7v-_0tIkk*(?j5jpEHwP8OJt%e7_~cVjja|hAme6<>ay_|7m%w#y$Rf1x z-9?)B)!pAi=w7GwDrrK+PY~#R7H=P$h5yN(^)?){ne})Dra1wOHJFW~UloNfrG)YX zIM2HO%{fw>PghnLez>23<=v)b;_L-F7}?lgzP+OAK8%Y-XwvM<08O;36r}nY1FBYj z^yTN1>1gZ&0SH#XhDAlM4#3>y@t0>=0~zbZ%=j~?zbkjVqCWmnQQjT#XIg_mtlh(ib&iO8n8WHE3dcjeJSv zEzgqt@Nzt3En~pr#Z|EE@FeG)gAJ%%>RiKfQsa^TSO%qf%8V5i`&Rd2A4dD$-ym9* z3`F&Akz6XuU~7Y}qaYUKu$MBI8H~g9DE*aN*715{bx&^ZjYxLH7yQojO9((i4MfcY z$gw8O=)x`SG%isf8MU`6_7?bu46MzVNY@`Mp}fms-0$ktOy|aGuE(1?^!uv|hK~eX ziLw}C>V*W}&8b|a@?l(m3^exa4`DiqEO`C@+mRb4M#6cfQ8VnCO9D<~8m_d(lzMeQ z9;rEfAG@|$pSYX0w_oj-ZLV$} zt*lREsV#~tU2H?owS*;y*M*>mt;VR)ih=U6!N_LTsvTWK9Wa|u#N;yzwLVtFg4<1h zV+ZaG51;czjsGC1(vxe|!L3SzLmG}7g|Q=KWxyLk2Y9i9j=uk*q-t`S4VS<>8q`fC zFqIBe#BFFN^E^gdXMA`V#m1Zgy~h$3O_NC$fLByS5b3Y7IW{(CnqkcJfjxURf%}Yx zh@F<&+!}&k0V=X?DG)_4Y8zBDgpcw*vjN|&9p*;q)2>zN1`?CsQw1dB^Ei=R{et(3`-*39kM2WI?Wcv9IuXN&z3yg5wShyIl>FqLX2QU7q4tcEkc z_u!ok{lK7NLvq6@*nyS)#D8$pc?8d$H>*R9e3KX;=ovlD=B%kT7bpy+jO>YA(E;Ic zp;O`R%u20$6dKUCT}2{6BGDr1qE5RUKPn5POB8ey!hPNaD)fRcX}^d>ENY!S<$P+s z95au*T1s0$?TI&lO;L3g0KIpbzt|{y{6P-qGEqiQ z4b?x7i&z1x_025TQv+!t)gZ zdB#&Sj-@O8NA++#M!X23+H}NqKJ$YGs#E9pe;?8<>iqf$lE-^*S!p?{(G$6y9b>yz z{wCg;MuO&B_Xz^S=&&!g(jvR<6_tk`d|R)kQX!d13vqQ8KeaPS6V?CxU-qv|MQTE$J%32QAMvUT^o;h(BcH2QMzuzEr&;`?YgO<8JO zA3Z7P#w*3V?OR5`)_X zKV#gQ#l;y|d&Aylm;8hsW?eN?w53V`!)%pg=wV$0$rYwn4V96PSf?h2cH1Y z=`gW+4Ycy8P_g*-=w$44!c~)s^ zkP8;KTNI#enwJ-s{(2QMq~Q#__tg;b+7i(O7yi0gjDch)Le2(#Z=7CXX98 zaN;Y&)B6;Uq4VbdUc^;!LZ{ZEW3hv7*0ZP&%uMvln8BJeuF!5tn?vL$0x75U^uv=sz^V#$ksT!%{zof))HixMBV1Y213t) zz1Nysteb80!7SQnLdHsF1qX5)-3p|2m_9y zwpxfHkb@sm{R6Vc6J?rx^}+LIzCa(}il%muwyY7QUzmyeSnnN6xV7cDI#!a}@1lX} zJ*}2iAuv_IgW(#=YOyih*BHFx$1CdNEUGufe~_)VJdzVEuBOzbqyeGpx^ix2{D zXWzNu7V?UO)5V58T6u-W+((((9+`MMmfxFAM44xNz^bk5aLKzvP?*Y-r{v|T=kaQw7I zVVB!SCY-0c|C{_Fz^YNgG%oMbd0k4?u=A-`6cmQ+AT48MGuK?Z_U@O74Eb9~j8%eO zg3~?{@v)bxLG+~uEsxI6;IHf&c$IY-AJ1EEDp|A&^~jLwr0XBs4eA!(%s0hJsNu1v zG12No-cf*^xzUkbM0WxSH|Bu={LZu??6m{X!=itDgEcoYbTYqTo2L8G6gP(KBbz<( z9=PX^yJd6aC0v!9Wi)xb`d8W6FRBbW)6(#u^A4TV`4_Hl!OtV-we1djfdtT;qMc&zK1xFV!Aq_AzSY%J-MM$ar{(#|OsVX$U zstc8_^(3giTCD!lfl6w5{>*s&ir4D0?#%ml8zoMMJ`Bhh4~OB?(>Pex2DQvtpE%{_ zP-UMnu1CqgEyRA0YqTKuu~_R2G^pd5kUHd!e40qi2Vc~r7>`=Q`Lg3x}w*M$`QP{(7)ZPzid4-BaD~JE`&|Keo=!0$x zQmr14A&Wi^0siUT{O$sxmcA^tQnN%3hJ1FKC1$e@7+-0mCh2}Gsj(Fdf&yV$2vxut zfCoMp_Z5c_F^?Aq(LLW9U@U_h;ye16DMLcOTAHV4P z2eR9d#kf)5@=UP_v!68|2L!!SYhS#AkV&ac=M*9i?&Ds}T@&qS%| zpd6wXgShkw2qF(`6^$?@AQmp4X8=pjjguV+F68|k@HR@NK?t}h+gdCq2Qb9ho7E0a zPy~xvh?#F7r1l(eWiw%?Y==?&^1f3frMY+~-N^_tu|{W_mU?c!6-b>xvo#NkL)Npg z@x|6gFl<({ae19{Y4o3%#k^2!tD|q`feeP=Oc4)Yp4>~pGP{QD_!z$iWWPc7c=4RJ zK+yGPK~#RuL5O0fels<%4q}xsTJ|Ppz+JHfEl-6`oY`Z7r$K~gZPozI4r}xoFB*nX z&mVund=;sh(wg^diK{0J6RSjLc6Rnqe90$6pA=gP9W zB!Dg5+zHt+`m8H-MFf*$3spvE=Ep+bXE&Pu-%&gI#|RS%fwQtM)Cu6NPGB31@}Z%I zW{L-&HiIjPnukrn4e*|W-~I8dn=?Mpw?b_f{qlY&>tU;InWTiWs73O=hO>^PBq>@b z=JOyoOjHh$)i|qg z%uj}a%s~p3 zkRIIf{jye}8K?`CAeDzX_;?+5h_gFktf@106!^Syy$g4yapP;VtvcU z>r_P8w#&SSsjmtR5*^I0Q}ZRVW1t@36WtX8q=^tE9(I?Pif56N^J{Aq_2Uj#PQdG|~hXVpfwNRIWP)G7x5X)iU)sl&cn0?>u|t%zq@8{dl# zJ9```@iKbRHzRBr@};L4`@;OlC)=^S@1=1>gt$_1m`P2fAMa9SwDrAq_0Owtn5RDKx0`R2s2MW&QM3&QReNgpzFAk>a`m8mgopB~ zKwvIL^Sa3avk13c8>VqjLzzaxt`JpvBhno=GDK_g(LI>j1D5r`#CyW*QMBV^NtXzG zz#)e>JH6jkTcS{z)>+0yIVx~$HJOuZN6sC}&cNsA3myel>lhg8xj?&B`9Bpyrrhc0 zpBjG$D-*`M1eiuUd2|8t_KO8;3)rq$E0%P;y#7a1uXi;!y9(ACKyC|96br~ga|T@7 zA?QJ z-L84xN(?Di!ez^3Zk#s7TfqcLQ!MBSnH?-Rr+DNowqz|rg+V0)Ib69YV`Lh$iF5ZW zf{6XlTg=f+1=Jqbr16N|<1A@)4n0-ZdOr!NWltJ?QamI#z_Q{k3s>QV(OX`<`%};F zFGC^Lo6*3ffxH(BW}n0h;E`lxvwi^)v2nO5PgiE{PsgKw46We4=#g#*i=H54n)uyc z=jCt-VwNJ)JnHRea2tBDzT?9A{^}L;K==N^qF=T9IjaNvIHg6mD4J&8Qs08usxbsK5H2xI> zV%lJ-(V){EW6{{{FxWw!c4aE{emYmv=YlK^BGBE19ydNzVys&ckx+b@VRj&=OzWqL z!93=%5h(WYYD%HU{ed~)Hd8&<*-t8gSVGV1yr!Uabjvu1*3^f|-kfPC0jb!%uj8}#gpr3f>y}5mrUnktCTwv6As>%U$!A`vDXtMY6HEEG(m68k zLG`Wi8C0Te+V3Ns1Ch{UQzAfZmsO1+{gTpLwuyK4;CfQ=s?M!~pdslrYwLT&UA<9ryOz96I4iO9lG3Sff^fD5M zeR!bWMPZb4e?qBPMAzWw!5x=ny)txQcEdBue{HcK;j`a*z2|cg8-mJ5vd*FNwtI-< z;+^c`6}sxPni+`#rSCIFW<}|0T5DPie1A1mTe-;sm));R=q8Dkj9@NjP4+m)@t(ry z_b^ljC4#CbkVh>=$y<&-k;cE2TqG#2Vsx1qevSd~(Gh$ju*?AGKZ+WDNFY$ef)0)~ zL0x%)w@4CLBV(~*8Zhsz!6HjRo2cS^H_1e#6B`bzbM2v$>6v(c$^=TVC7d><)P%HUQIAWdZ((L2<75Z6i*$1y%q!`)xF9BDPV8h29-DC7`;5?xV z3xA8lK4yHyEB^P;Lz0&)S`XeXnW+pr<1hicQUkd>W~?!?$f`IJbSlM$|D~O~URUAq z$4(zWzt0crHAWu~=dhjz*$L<`ZB!_d-Q@4Jf$E*EqP7o@3s{+O-2MhO8^$25q1Hp+ z;%37Edk`34wEsm*m$GoM2}<+oY=i4gsnq(UEk21DLvkM2&ZJcf07C9hIw!9veqr(K z(_=!l?1~bydht4Ax`M&rZDhNTJCPA14MRZtoErBqNZ?j6HD!GI%%th{&*H6lW3Beu zr`5r#Bj=)JsXLk29Lp!S6NEg~Ii4sA<$h3DSmZ^G5J&;Jx2z@_ux38m^xq2uv~z;b z9J=x>Ncj+-|FZ^L<~uo410mBai-91{fhH{u=W`1ocq3)0&KN`49A4UFehm2;rSk_k z9l@nly9&pnscIlbJDO&P_tUPjCc_>Q*_-m4MUcM# zJ(uW-(KQH6aw9shAs-Q&Q*M^@VlBF>vS_c zw~4D-f`c6m1?HJ|)lZiYOTdR_#j;b{DQY1zG+BctYk*H*(86CiPwD8lUfU}P?ethm ztiIHs(tXdRKtCv=q-5YtYum2mcrG0s=}?Jo)@CR=V~s5#MWwrxX+6Mj%H@G#=)DNF zQ>#J85o2(_%*0Mpdm zHY^9&<|DCYMg(Ou=Oeg9Vn-OQDx-drH=`~nxqYQ@aO)Dg2z??ON7w~#P=eKOF;(k$ zcrly}(BPbgx_T)|faWY%$^`%jZqt#eYJ1$Cl}U+ zHMs?ZP4Wwrv$cg5Dc|E)!6M?|$f&|zVbG0sbONsBa?)DwtR|5ZR-R3)r|Qq%D8$!_ucC&a*_X$g z7%V?>jBSJ*C~I{>=Xspu+!1)@wpK`^cTjZ5gLZR6W@pAe{$y}K>JaDNBvDeXtvjIw zUvwMxmzAQTkE0y%Y}$gn&j4cwh9@`n0}q(+NhlFCPV@-v1$mcG&fwtz?XuXn)S^G@ z@s*X}noxlF?$8}+$!mnoje>DR^CoxvY8=$c;u(J)bXR$VzsZMkRzUjZy>f*PzXYvX zOXjDF2W?#v^;D}c7^f$+!e#jWV5*>?gL2rigVM?kW3a%>a>a)i5i01==3-X#XeTcG z*~!dUv7)K;3huh@NZP)o!>l|6)z`;*p5{V#gBy+U=O= zDQ%ao0&(&nqMqk#ejM`+0VTXpE2!+Vt?pIhz~A0v)%z*FdLsBfLw<>=tH`+P6X`~E z`<)T^qgY;EUz6J8sgm}oamrCRfa71?Ro!A7@gDG}N-?oHY-UL}=LY4YHwGT*Kcc%Xu@*#cu}JUK#ZI{Phj_gh$rJBvzf$7W}kGm=RC zp086L@ObvOQ{VQyc>7cV?E#a%UMmEcF7hI*q9U z5rG)DVDiB9jU73(+?wbt%~`5>eaT}2loD+@+BqDgGn-erZP=KmPAg!nlZz`~{4)mM zh%9e^n$+VNy$<>qDi1FPKraSr=gS^`Zz%`G5?(rAmJ)MsZzU@hWIywa@*<8h7%Y^)CRO8aDfwt+)*#se}z2g=5bq9i%W9S`IkIX>4jNrM7`U&XwgmjaUWF zzCg)0SjzO2lCROcEAEsc<%YA3omU{xiWC5N|6H5hLZz=}-8GG%B_nWVeF z&?dO!2ZENeSTGwklcQL0Z|{Zi%Fqce6v3D^dafB8W0E@V*Wi~&rXwK2-2yCH zT9JyoG^w|#AoFICCC(3LRB5M&tH6iaD*Rf>#%KD}IDk++C_G~yDA?u7t2~3S&AEj) z#l#*HH)S7@cFXyG#nj@;zGdkuK}C?Z+7EDkH zYNH1nxQ?UM%3ui!@1iC#9~iX=(pIJ&F9xfV>Sq?_~6Z^lUzn;iZl{nUrda1 zT6`u(H?pI7Ah~UrD)l-^$qR&*wC^73X-uMxeuPolMc@JEIM;YgWj)hBvB{)G`9IQd z6@^5C%6gF1g<5&X&sz)aDz6dg^;^Yfm0_L%MY+rqX|GN1v*s9J^gXAT4xqXE@F1t8`N~ z$i8 z8397r06{D(WC;#)R)vCgl}%ui;d2hCC$FBGe3|bG~Saz@U~cK1u8C)wdK7a zDLX{IRJjpF1WfNi1Ry$hEamV^9t1Oz@UFClQE*+Ae|wapQh4d(tr)#RG-BodH9o8w zo&mQOldJEq+l5$N0Tp&nsdR>WVJ60>futL9 zc_A?;Yvk}wIO7B15_zgDCZo{qLFm}hV}3uVS(c z*Qg~Ac1lF7A0(Rj2WZHYA@S5l2+d4#;<WLN>;Py|iN4C&SHM1;%OL3k8Y<3t43tguq4?aM+BJnH(aaDwxmt=sH|EsY^P%nkg z27NE!QV@wj<>hO?o0Kn24A3JA5Cm(#Rjq0omM0(lC+P-*85hq2g;e%-7+gL1jy<|f zw{btoF2B@>7OhD&G1q|%b<_b_Dl>rwapXi)b|tiw-_u#8k{uwva2kg^bhyj`=bnCz zpq(Y5@FfAP&O$}f)-lc#SS63Hr4u_s!=4^8M#y&@4kT5zqfpB(78GYua#r~tZ@fTv7fC0qt<2es4Kb;rmci}vdP$BPM*(b*zl4C1O?W#_F{7_wDr2^z2$rXhU^o>nN zCh{Pt^zSvxjsS(u20%W07`MO}n-96MH0dJqQR)(*ks56-+ntg_B!&Q*){D4;7H8T* ziQOA2p{)NaKIwj>DT5uay!8?!!@x$1XVP_1;}Tm0u+UfdPGdq5`Em&b2>(R+I>@Qt zyo=}`4W`k2UfS6R@BhZluv^^hOHjB@mzeHY_gY_MCXCLvV?GAI?4O1TZI>IH_wDvEIcO zPyiIkwOI<1^=9c1fZQAb@SV2+8wB#mu)miZO@83z>dZ_DZ0-?+-fl zH2W%sc-=cyS+4@f|2;@U&^dop&A0?&uGMyKOw-#i-)?e<$YvBvg2Y%e7~d1`tok$F zjWBTuqp>BpyfHm^Q(^sG1z0Ke-eA)CN~mv z94w}8TxAiEYkIhLGd@r9yVWKQMwjThq|}j9RLPFrrDC14PKqjJZkBEz=1xkV?plu` zkXhZ0+l6!j6-qBfy}9U(z<3E4%(t8ZbM5qOu+j z)0FlP*O5Eq2zQoK=4GF-UgifJ+ygd)ST#AGN5}0`9ro*}?>Z8mD{8;c@c)xS`F@W~$d=;!1h z4j*5r_)K+WS$C(QBG%U!XY1FvSlMvHY?!hH%shjs_}< z0#4H^nHhe-l{Nm{|0?TzBgCTkUbqBevKW_EYj@1L5RX<~HH_H?53vU5IZ?4lOgWj5 zqTcuKR5G1U_8(YiB-0c&b_5wJ?!KFGrQY4k0>K&7A3?#p8xObEmr22FUpkqzy=*gg z-ezm<2_;=02O=v+)8hfToE~mEErLLAF05cTbug=iQm`>WAr8zyGz@i8l7;U)b8;st zv+aHWq-jt=hXPg6n8|lzC8qRB0q(_dBDJXAcVwi5y&Y}{fW}wP3$t$@Y`;=XHd@^r z-j-=xP}^R7kM3+d&DxbJ30Xo=U@h1U^}uj#P*gT<~#FlPem)hfil_h)dCd4+q4^^i~Lku`lm-# z8R|~s>|V$KRu?&zdl5=j#ZC-7Omz7xJd)ooAI|#M&N_R0aJ9RnTj)$AI5dKl4qP=Y z9O3t5bmJZ8sk)?_58HML5ofO}2(PYUPWRP0sY8+~b8 zQAvFD^fvyC!8gFn?C$&@8V)D%5@?GA7@$qxfNHCJ z(N83SjBA!^!j{nRio0Cf_z-#W;z+$ty_iEhbU7V6*i&>NM7Z zBg2>$9mNkWVn`I#5xJa_t>8^cT^S;*)vCj^7^uThazGzY&P2i9aOcnia5LUv{`iXi ztqq6gk?CNQ8lqKZ#4$68;iOWp?;JCCtW{4wjK>WcorynW9Ce^uvpD9*px85L5&!l) zY+;>233KJ0G?B$x!|lJXTGjUHa*G+SO{KhrAzW6@5rD?!DK}yN6Aipo5xxDWm)gE` zqorQ^;IIT8upLoJS|xUu+e{HBL)n5K3PLS3i&htjDuO!WNWG&-D`9pBHeH|#!N^A{ z;{Mm_mVqX;A<+U>g0Zak(pl(fDzRdac>pd3h463ZD_u3=p=d-k`&F@ZuyFjK%vEz$ z0$nme9>*mOs3fqSTju2*x|YKa9n`V8M>%UYSbIS$^|w@EE8Lg21yTMKj3t^Y8Xw}{ z&-(vqDV2Dx@I<4I_ZLCD%8b!{Q~e6XC$ul$VMEPQkn|Tj_YqLBDqqkxq|ASn6l=SM z+vb$uTOdNxe>PG05(0DoX`lkECr8Ybz(#v`4fil{OJ#wxEP2V0f+kF`cUUpVT~LFC z#lWkK$xhPl1`0{u&6p~Bm9(Ef#@puNdKPh4c*xMjFc{!|KR4+0=V28$Zp;5yA07Nm zK2%7S^a}LwyHt!Dg)<5z_sgE_Vi`_4^$=QZS^$;k*5HbjKZd*eCvLv!AD+TqWk&!2 z+d6pZ(v1Nlp1}2(E{K6wovlhFDEOWs!BQcJQlXTpTxtHH2hoGISZMy%fGoAQb@N4B zeT-(q2nRD=|8r%o2H@_B-ziZG;F}e^69HjHksFyBw8;(P9VJa>Lq}#fWGK?x9wCtR zQmGeG)UrfFid%#7&<4N&=POPHiGtiVI7J@ayh=;IwZ`-=ff6VP>k{>-M-O0P|-ym7<&WZZSUIdkY-#oynz?bQQK{`1LeurX^JMUSV zG95*`Ujp*xX_CuJkiEjR#IVTw{JNd8xzGPwa12xJ`u5DK1gp0-Zq6Vx-5-#!>CqUs z*WrUKTQQ_1C3$g*9JKe;HCcMC^AEaAf@7>J&}g~%@Vf{aTLNtxmu4_BUrtlbZMzl{ zJyku3!inVk#-1Ayk}%9+SnInltv2eAi(i0HZMSB;Jj>$fkoYpaHYVwOJ@D0amRY${ zxJt?sCk{6EJ3$qZf*-?E$`-jSrEY*Yie02*HKC>?ru5CZW~_XnJU@tDXYb_xn!+>y zz0^KODWIE^30^zsn-2%o#S9Lyk7peAZAQs|TGiKc#gBIwMp=h?iGE1bcE;P?530m; zp4I6<;4mVA61r6kawZsdif9K1+!oZ_c+m;wnNsl;yQ``z+{ zv{U?$WX!4uP+`J9_aj?C4uZtAlbvHBh&269mE;@m;+f~3AoLVff;{$cIxPbLuHo+h zQ;c?xvG<)OCUV4Zmti_1J~!ZK2c>SAmwwziKp2IbT}{m)fzJ6kL?kTp=*V9;PIHRl z|LDr8yuTQN?CkZ0;J7=EEtiY2*5{;r0o*uhL&#+e0Yp0-ZR-1)Mx#i{ z^?r@Mgv!Y`-h_`h_j`*vV>A#_R;S?`PP_GfqX>t=vdY=Kq>8`HGB^SYf_Tk3=mm8Q z#7(^6l5owl2+SxKCQ8*}M19hQR*m0OoUC+qjZnH{-qN3X5D!%Z#v7`f7BIH5`>H== z=@cTq_7b?_gYJ_h@Y;LOUut^DTOWEH$5jOxd1W@=!)!ejOdt-L3cOHKmNA^3}W(` z>U75EYq~N1sCT)%IYt$W+Qi?uxH>(jetUQSxirF_6!O7Jskj%9^qAf{J!F#Us$Hmp zH>XDNHggR9w>=Q?Q7+*>|5`T;OM<%`LiM+_b`h<4`36b9Wuh>y>J!r$Z~YW`H+8X# zu9ko)q}%T4Aml>Gr4Ci=PI5zJg_g$8S?Wd`c)R)z2x;1lpMm33le`m9TbJ#A=u=c% z6HNhwDJ^FRi$5iq1J%kPvSH5Tg&2x{?7{*njhm8luv`-HL?H*b&gg8O*K}-lpbw$C=B*g&sItf&S;*~94@3pWEH!yok7oEWb{Ce(}F0aY)ubYi+O$yA-eUp z&x7Kq>Ma4U<~&*FfpE?K)e%{a7x&19ziA4EI_wi{RnX_o0ac_)2g^U|rlUq};teT^ zn_Sm?>e3%2>R+dr@QA~;qvbBwB$&s%QwD&rDA*W^7r`GsX0br0^q!ny!+lQM99Q}o z@2{xY?3U-a*`M_-r|Tmp0MO_^PiL0>*y5Sc@I${Y^lhqYF6L~zl$1gv<7(Y`@b>nx zZF=ARH>>1WD>?JyG6Uq*DaEo}yW5GFxh8d-+Wp7Au#GX=lZD`Ku}Ja>S8D$X&q-7Y zm6fNY8GP&Bk1bWo35X`eN45TTECAr5sU6BMG@>_v5idO(90P%v^LH=weOSdREf-tf zD1KPS0*R!tIqSxaI_r>MG?ZNUzdh>}Yn!n+=ufbmneROBZpT-T6kU9g*AdZ>GTHk! zt_#VPVAb=0#BD|EDBTCaq*I@WB}E+;ywoH4eF=ti{0D?8E`Ug8;S17)2;lZe`Hg&x zKu?QFX7w3mrE{q**5(#6ebU83$&z*P3}WO=OObF)b!EvI)t#I47N7cGFUUMWG~n{; zRZoqB8aj{WrS$3n_ctiyNcysebz#oW@-^7mRf)V~Ct>1rSBmUW?bZ;-dbl|61WKc9 z$F7C=f(9*IXK_XOq36hN#270QCT#8Inwa;YF&EkAT2;Z#4PWqjg@xwDj~*aVs%D_F znFK~ZQ}DuJ^_ZANH-L3nV1BsBuWvq0!(yTIEq6o?M_$?I3n2??I7hw&vKbm!#Kl3( ze>g*-)A~-hCC(OZ>SRszoX2R(Ba6;VsWN5nM63u)y&+z~(n>E_=d}uyu&MOSKm#+E znSX7J_;E16B0I}9Wvcd4?n>`bE$c|H`B{LsbyaW&pxaicaFD7Hu{xsXs%q25Ydh?& z1u%wZt&;8O2b~xoHWQ0;xpHW2PLkfRV5gfrhCVvqx zuRyHoSaQ^dGu6TU!K9j?qsdx^VFpl8ib>tlO~|aSbTQW<$9|x(g4!&?^G2%Mt4spY z0NnG_z5RPCr=^n>C(%?CPBXt+f#;%YPsj+i5eE{174M?j(zp7HDK$BcFV2{C(;R}6 zRHV$(>C+I6s0}cm!6nx~_Z-sXjPW$LI73J6BFa2>?(qrOaX0k@-2s@ettAE33Ax-`U!EKIK21l+ zhlpLr{4m}MkI_p%yHdT=;G$uR{G>>P#D5quwU&R*BLPwI+6bdqb4L2+&^ooa5?Ti0JdXL5e5 zOm(a3ID-SxjhZM<>sxiIMpNpP3@!GI|2Czh{kKN-(T=fWOlz92r%0^iE;|h`70tH* z#+(3m+-tITrl-r$m%LmLjeOmKD`_WuEn(t(%5aWszH*va7nl9K`LR)I{x!VcUvj9? z_#KepHG{vxCOZr~FY0zKD!z)7hu{r(vZG1)xqma~rx2wW+8=5L%<^SkOUvS9O|2-@ zWFRrvQ?J|T7N~+J*LS7<@nMF^L8|Jb1l{KE8j{Z3p-^_+lvT{;SXa)xBr<$M}tcfA9z9V0AG8*`C zOsmpSmh?O`r6JnvYr|eD@7i#*^&)zuJ)q|B`eNve>!<>Su_+D=vY^$XNs=Gu)%cAj zC+BAX%RT1>BZj&0A9D$2bQ@zC-5xI*UmY}>RVkno?_5`oeJtEo{>r#l>J?eSJ&`du zbaWN0ct))Y40+$z4>RK5*GN2F)T2YKEU4b=Vu5H&m|6_Y#ztf3tmFU-_qLd|Mfx7C zR$y(CHV}D-$GNEqh}Q?80=Lv5rKX?+0FZ+n!7j4GG*oIyXd7 z;%exX?#q5lXBaBMPK{?8VAnzj+Csc{!{oE7$-$35hgV`;Y5}NwnLi}Xw0c>MamrzD zjwYQl2+;=Aoh1@Q$ONe(2NUC6;FGbXxg*xd)&2M`n28ynVq%L@Rnspe=IL4i8Oar> zQ)Tf$SA~F(;S%l;j&})#hnwqcZ(;Ys5go^#*9Duzy5KU9pfT`IM|0p(=9U$GK+=P3 zIcP7$c3Oy~P^EmjpQz8Sog^eG0Pezgrf`*rZ+#bOTc^LC|1%zT_5z-pvZDUDi7GKf z+W7X?Wi--eLL%`_pGJ|=aoF>M2kdI@(SQRwNo+>y#2PD1-&G{O>oXUArRboB8WdDe zX{3r3&Rk4lz@4k>1Jb&vm&Yi@q2Sc{K7nG+P0W_5yIA#|1CwCFDx;iHNF?a;gK-%A zA1iUP8-|^15CmGq_!5}rAE)TSHSy7zy3LE(r0{5!yCw3({`+&eOa7#xD4^DAVT!$( zAxU752Ip|dlzvkh4eU4CPY7q{$eMD3fHPiB zyq$34=(Z*DJFFz>KWF+H1&X1jR@^eMwg-NPM9H$7!UGWa0YcSBU!S50{UB4sM&ow~ zeG_u`$@@l7>O?{lDsF|_113v5`+;5dn0llYuP-1&?8UTyz6R<9rboQyrtBW*T@)#v zzY?_xCEbrOL#O0977|Jy#|R170+RqAFGMRkxFn}@gHyWbm=BYiVIKSZ;pz7rjHzaB zvb{r+Eu5LGRqE7Kl-BPyTcxn5@q?dc$#N(2$wUUwo&i0Pp{eC3PKb?neT7>nnpA?1 z4)sH4vwX8;k>!h}$<=B&;g{Q|@+?y`F{V>qzffmb zsj3exWT5n7gCzSCEit?mJ~cqWrvwMO^iqP@rK}KTKs!iPv}_C7l`4w0N?X?lf-%1> zY6ER-XWBUa{@>T)RM{d{Z8}4S2Hf>w8+7O{hN5AnBh?!vaWzfBj<=DTQ{cH(-TO<< z5Kj&9ZiZGZO(G_zsu(uy{K7;|{5z$HBhWxeww0qqX^4X_hEOFqsS-b_6*Lr|_L8^* zrd#~)g1^4~G(@j(qeRYMW`7+w$P+zN^48mDY;<%=zj~*o%4iZjwv39^dd$DLDh&X9 z(!?Iz!B&d~&~kgI<-wWV>lSSIB{y|E^$TvPdpK11D6(Wmr?w7~2>`z5TOJnx()#=S z<=g*M^`cK)T|BRkJV^=K-_j8NUG9a{E7CR-LcvIquWfiv_RSQHJu=VNG_hWWi^{PG`STb`B1etg-ms>}=_y{@ZZaZ0c zbq#n8MTMWdlxD^EZ6Mu=PC#Z>JN=$!2O4)GGeJJ@GX30yBf-#`nQvUQz?6D$h(579 zIS>8?v7p8z=kt{Jzz-%U?Hc%25k@R292|~3S^lek*2_`fw)dogH z^GN+WqtrOp5eB83X)3ancwqM|9dI>dkB^RA%HCJ2MSj_lYokf!r?*?n9HHi8$+NB$ z(1u?Ht2*6|k2FNnA}B_7JatzEnDQw=*-c}GRH}H2OThpK#l6(U!OIi@6k?5fr)K~0 z1U+~?rgu?wMtyhSJmWX)OUS!i)1k|Jvtp-&YWdMATjoq&$4x_EaS3eY2hTH{ z?tP0D^BD%U-%P}eVKhlE;_t}k%Ia`-Ga!6^6D z62WZsFU=5!K5dDG#(i7?L09SZ8W($eBL>lo&f{MK;DYi|KQM@0=+yEF7<9rWwhXNw zBhZ{~1@2(u2SJ0U0S2l?06Ybzy#%pL@T2ayeS_YmX@a-Z5%lm@q5J5O@%80mgY&La z7PAT3BItz7Y#G4KKD!&5<$~Dq%|V|Deq`H8drxd{GYo!4}zj?bp zjksR!zPerOP)2^72kQAvj#DkusKI_PM=WL*NV4hZ30l0CT^C0F&tDuXcJlE86zvG{ zePX*Obn4IZg=XT7%ab1asZH2m|4e!0|R{-WJ!a(=Qhoh6c zrSjImOu$`Zd_6#~c4tmNp?325Jz}UBj*BqdPD9$bU3uu7R{-}*N;rvPr5A}x;3FSx zIt4hu`x$ zx8vDVz<#9b;)d@XBJQq`uYnmd^*LLQj9{e+$ADAB4(M%B3pOv^FI9Nss$O$%Bqc{Y z+Dq5P3vant4XFh^>;ha`#&c`Gps^%g>*{7lrqN|_Ri&LF_6Fw_1JhqO*xlM#KtX^u z9miLjs#etj_C~(82_CVfT*K1JMxWz+-vKy}kE%`-HuXAtEq^+PG!Osdx~0Nc(SJd^ z9L$Gt`AAue_edBZBYmX1O7bj^y|$(Wf7eq8qb2FW1)gk7lZ2M7HN_+MH5QTHdoKcq zu!E;X?AuvnFWaeO@8>EThrLaoOW%nqs?T>zm|0EMykswyA?{~TITtrw&2t**%J59n zXTUu$e-65_c#AvmOcE zgpoNv9S)P$C67;!^6kHy?E5Y0rbhW-4e2*Tad@(X_})Op1t3@!OSR; zW zemi?b!E209K+7v_Vkdr7Z|$IAx%Xa*v_;!lsP4#|TGP%tm+4d1e3ALP-DM=pkIY}Z zi|=j!K?_0))1}|e1@n|)G|RJAraGbkp@xKEx?<)st-^fX>0DKuw1hFf^jy74NX89O z=T4GL@YiKd4$Bh5p?5dda_S)OUi}3V?V@csoop{pCs#+rxfhmvp!9B&k-*2QG0-8c zvH~o7XIVVh>LB3AR;5A}14uWWDDxwWYMZebyEd0s9cUW|7wMPEein3TE7netLcR`F z$!Mq=qzbZyB+!6V>m@S2XaW<(5fpi$VZaA`; z*@BNVA{PNX746u9oeRwYJ&K$nJx!5(%GF$emQcpY9zxtcB+Xh>>1dgV7OAjJ-kTpH5RwonRv5 zOH!c!mv^MC_#u)_*{Ot;c`@WSJe!s3kNTZ?8b#+kb;PG^?tBrB@U`SPO8Zia6f2$B zwEXEJw#DXcFL%*q@-Tx&z>=Je;?wd&~yy+b1O#@jH zQxr!o|5^UF$IZCtC@%o=znks~qzukE@k?MaYMW{&KL?zBx??f#TwF+F=N4|Eg4Gx6 z%q6Ftdm;_(vb1()y`R1zv~t>{kcRM8#!9NUx3xxvX#&#T#Wn#u6Zco@Ed8l)B=9mXwSe*=`k@km} zCTC*RHTLl?S*SL&B}$;QtSKMlZLsgV(9`SUOB6iR?}~pVQ`|B~{24*)fE2qId2e|; zF1PZGX={80WlOvqwZK{ECL;^fA5Hblrl7OkO+u%E*`2KlB#hu|whot;<1pTa)FC?O z&H3(+#6-E1mslXp{elJ%1sJ2!yh;QxB>e`Bm9)e8#5P&TKAHiQCi%c@_ouGXPejZD z<1Iv5_hevcwUQ#QF&NMLv6klK z!@Wc0Sj)G_JNP^E^y^>k41~mPSs9YUB8hddK_)VUdGEA`j_%AxW8ApcAqLpIKfh{x z30u%#wWXApo-KhoZbEA3`&V{sS>bL_A^u8{xv0C^UC&j{^?3CFLwgU!Jc;EuzPmn- zD#%B*SY!|Rxuh$OrLz?+YG@l{1p7=@On#6E=dwWrqg>NUn$OP`klE1|&v90v?d?Pj zI?EWnrHKy#t>Ix+z4e74NXJe!suvH)&HLDI^$p=cx8jYoQTi`z*@@j>H&)}U7{nkw zf{S#A#0Jaom}*9IBAAh6=TVj; zS66WwfLt`SGz1e>R4zZW6I%tzN_9Uk;ZV-l+J-wR28{%r<06OoV8u#?Rf{;G2YPMm zRXRAoAL&`W{tKVDI!N+;zXk&&;P(ZW?VB$yzL&ei7sjL5*oj7^hjBA%=0!#Fch~nx zkZ>nv?je6EQsC^?6Crhq#-@Tx5QL=KrvF=*y=-5|&^FvD;b{rCtihy53fWLaI-Cu% zM2>igs~Ov{prkjaHs%A*OJFe<0A|m_k>+4d!1 zsey|5N=94F5{35Ckn-*5m#D<Hb zECNX*5a-k6JQP`M2j_hZ^Gr!Ct`#Gp?qHA55zJS%@?EnjQnz32^ zzJrDNH-IFr?iHD762O2C=HU)V=L-v#5)Kqj0UKz1;N1`LTMKvew_w ze}Sgldzv?DTHHxpu@B8XmoHKO7~fRhCLz}F;l=AJ76oS^D!N~4B$}37b(6)Ji*jED z&)K9=r8l4h}rxb{1WUeT4kKMWN1R(tA(O~*p5Zq(h9*R%M}ICe#?JO_O%m6*pT@ou zl@1Ovu>!Am5i`sM8EAX%f(bLPJAEY1yUqgdg(NLNf>dIioU${2>zTO21Raal4cm9c-x`Wjp+ZWi??W=6;HpH)pX{xx)WiV;La5GYCqgpWBM} zRD9xBE2?YY4~8%GCW=3!uo83psXrvBEXsGe+Y2hp$LDgs>U%$ka%aFIXg3*o+#ytx zv$SMc2JXa4J0ql}Mq|y%j%(+%tL_BpS?C|atnx13;ck;9O~*nkrT?@h zPC>{WvGeR7L>Qi{rxDafS=}^}5~iX>Y9m%h$?5%MnGNMR3&9l)_z$eTJ1nAVDwBUO zGKQLS&Wu-9-LQrt=IXu3fn_|PTD+_C-X>J;t?E>Ft;=+sEt-@!K#egnZ@Vvu+6|e`?G2W*Vz;>k)}9i)2g?zo^B4EyX_Sejhdg;v*S{W<&^1YEeHgt}G>p@_DBN z33D?6{=Xp&`WD#3jBSs_r=WJh`a^(#!@W$!!7GwQddMCCci^e$Wy^rC26{Cnmt9ys zo`rM5ujXgT)7rcnHLlrYLSt0Hd@W=>Hf-!H7FI@ZfJLBZ{U2(M)%c(q`xWradwyK& zX`Nc&a3B-gKd6M_`)EC9C0)xzxDe`UIW@<8hyTK?cLZP>UVuEQ)NZ7Cwi7YTtl|Xy zcN#9`2Dg6;Ie86e#njp|&y`a7!N}hbRB(OcEYQU@J3`4|Ku_f5xi`0A$uorF@mOx) ztrTbOyl{8|eihtfZLv)q?YwRGmrbM%`=_Y^+o0V%4v9f^YL73ornG>a0E}N(r%^L) zrpiFGmZS^(HNZO9Dv1XN;VkS%BW9ZNmc5r0Iy2D=+UI{2Z-R7(J}}AP$(PTQ7pG`K z5w6i{n)9?f+(PDB_(}3E5^kJkW`*fVg{Z+dcq20ZV6Jl*3WFm;@A;x8+GR%4A1cs5 z{sD=r$*E1byMhrSOz~u`73BQH*77b@o_@rJ{l0@#TRzM5JC9XmeXNJfOfnZ_{e3?q zde&X2%u5s74qcLOp;=wd33+eTHgOEe>9;Yl$c6z?>L4Y2saJwy62z*)Jc}vVYFCN~ zuE4)9%V$+wEE#GSBHhoLc67yngg?756f?(q17Ah;SvJ+2MXTgw1{gR+Q>S8>#; zZ>Y6KB5pjzhiFHLi7d?&eGNNk@6v>?4c)A-R$3ak*uUPBG7q`qm2_+6!2G^p0%vfoDXmlMzUgSL`Bo7viXB){f1ns9kp7Qve7a3PBfxaglzb<4f?VN z!B?7C`F~jrIYxxLUwYG!g^~oglnHtq1-~it8_QgT&NAC-m zvo`Vz)q?b(u6TX<_v$F~57d{%VsEK1nPkm5MEajQ1;ti@?~y-(4_-1B?ZqOdRSCUQ;lC!UkDYS33PfMaEoqP*tDj2xUQ^Zy{j+F8na$uWJ4wFj z>=-!L7*=_QcaVQk0~eVwwM0`p`4Ll`BAUe+jjHS~zj3UBPnV_qc}X`TB659H2abaRKASw2Ry7>wzIG0(|NkQ>9MV$JLgN;A+@UR;GY`<1z90R+ za?c6}CxcY@@SJ1oxlRZ&X+UG+&y0NEJmZRq)T-38-rTle=BW|vFQTcFm+fW~>zy_Etq1?WEU7!cN zIaZ|7oSkfr$Ux6Q_8;&Pcs>%-CkEQ?=*skoJipEniV?o#qCbKa--st#&WqXu3f z`6A_*xyKU}jtx(-+he#2yK<3Mwvv_TA#asf1QHQU6mQc`WOs?nibv?lA64nl zk5r1$pfFOU_ikA}8vRaCx;#N_p+tU?UetSslSkmu0X#X4fmHq~V0~Im^TJxIoX72Z zG(G|rm0n)}PWlwP5Nn2F>=*wA!@j=^n%c=F+wMmPGs>d1I+hn`HHCY0G5x6Joe~yQ zk{P&tdMrUdsU6>$gbe^9Q^wF2=_xH3d- zZzHpV{$4JmazC5+UPNIK9wHQ}j-#N#BppZ?)-Y?S zGjzy@Z?y9jp=A%#UGnO4zW=a5S+MHXa>^<_zy&7`66QA+7nh69<)36(Z|A4%DA}0T5EY1K42Y8QdF7O4a(ueeoOpe+zw^ zyWdPAOW=INJ$1>rUA{h2!7EPe@On%tl>j9=%~cXptK^wi%I8yX#wT!evJQvw#M-vW z+j&4TT!ymmR#R8#W|1cO*Xll?GyUm&i)R_r$AUcKA0Beg9>$!ZiNxd>)2E{i2y(r| zidmDjdVb~P=Y2uHL}6pE!@21yY0m!$&VYV*2$Q{e6?fi2r1eCa@D_S0v7zRpG#R}i zBu6iXnrx zA9{Q$oDLa2H~QX_@3=fcw0%MsH*4pCui8Yk;U`xWc2fpARqYEEiT5;VR$8*iA8VBh zL#1c4f|bf}s#Hu(^Mm@fn<((0#LM@zC=nm#EB-$|6o~VaLN+Tawz&_8iIUka{0Y2Y z{C{IHK(^ZTBegQcpy%gAbPzgSVu&0FZJvr^R%&EsBUwGC%U3XaW!|i$Jzq)Kay)O} zrv9~UrdD1?Ady}T1#+Cj=(r|jDq4E%T~Ya$#&oDvTj6#XBJhTNPc?bu@2v=Qv)_%N zB7Z-xXhp8dWkf{OJBR%89$rz4mt&ADZMhNI5fsNA9jCa+PTUZrFgPV%M+9_7hV*)D zgD(=151X{J1^p!B1+>HDnTY%s>PhdBaSWx5Xs=N)%yyjBi7rx*YD-;-QRqKZe$u-X z-}Mw~YYaoEa&rS2;=$C{S*iktPYdDpp2jJPg5Ay8l(lQJuZUS!rG1 z(Dy&+VCa2|{mZrO;yZF1>|grxy#7~fR16X+stfGE5S@;0W(`rlgrP~&`q@Ox==Y#> z5&K{a)Q)y>+B4lIJuN+s(pLHqbI7K~XJrQwxF%ReM&NnCsn56gUs9wLq;YzpJvMK-*8H7 zEbz^*N|9RGhSKE46F&-0+YDn!@HwL`589_H9Xg{$F7j^tVh&OSZdG?&|=8iWc-+^lr`*IWtp6B1g zN5qJ58(|;N2ju-YMH0jOMg`ADj5HE#Zb;4QIoVan1EJb%vm;(uBoNwPYd#V)S^~j1 zO6?h4AI%IeB_e%tCBE^ArN0jN>Wn`kK^C_>;;Jnw2c zp3hmw<%uuvb_jb$%8O8!f1TA<$3|QHQC&0vKrgemsHi&`gw93mh|dYchVen&D3! z6Ax%_C-r|Cdy&$SE65Fx>lED%mH#Pkl>X==2V_#QqJ|Kja!}Heg`@FL2-S`C`CXp2 zRfz>WHcQU`?G;&_!M~aaPSlw|-F0-3byf^gvRx;>tTl5E`MBJ1A_+8D@<(#1!*!mV=HQ19s0gNS3qV>%G1%miz*o=|e3Tu$H9SpR5m)Z^3D zS6Yal(X4s7{GI#3Yj8k0wnH25LqvfNrwXPj6w7YQy(#pMKMSnEdk1huG-AaxqPTul zZAkjTeiyx#6sy%6-P6EIqI^e+C?ukw6Hdj**+MPV%L`oNU84;~6`+4+a$OgR{;@(h zY|0NSH4`izx-jw^iSWRQVt4R1m)bXDkI#faxBqP!G{XrR)cB~^hPb(ZrsNo!xx6QI zZZA{U=p}uAa{2vgGQGhKSE4{L@ z7yZ=;3yeIO-Zp^BptfgS(w^gJQwx<$6_}6QNzrSZmDz~3i7F{i*H6~q1c40YnlT5Z za+5l`HSs( zpf53`;M7LogMUXq9&(puRi|C*$XO(7vR0-{84Ogr_qRe#aA}0OOZHuY=6E0nr_3%J z;%nT(YZJZt`)mD*fv(WG#Y{*)&B?T3;ANsblOQiZ`<}=iS`Ji9pux*8G>pBtk>{O+ zXHg4fD_~3CkJP|ilnmWDiJXNfpAJt|v=cd1^RA3#q9erfqENmmv+11lT7aS`glJk0 zYB6u;Lth!peD#^cg|oAJh^|6Ps~-c64)F~rI&a*zwg{crF?3$Xhe9U);_v26nB3fj z+|%|F55F$pcGYuJhQG^tn4U-2Cur*WE%3Ij93f#;I^WH?Gmva=E*O(n=h&AR4Xm-4 z4xG{XqV?}Z5BETYi`+ssO)D_V9fYi|UJ z8fTiAjOR}NpY}($jw2OS-AfN`!K^7bZr*~@tkrHi z^VJl>CQ!(V`K2m(jvNebFh!+?R3SJL3SO&#eAzG?CSOr_4#}Bna|Q%U=vVSdjrZKi zP*WECW|@T^9h1Dxea|0ukyFVB0W_JP#x*?7tp7B zCgX^U>bE_-oLj7wFG$9OqWK-?H2+a8QG; z9kUd$JomXK6x{N5m!!Y`k+Q6AMxP%X0y#SYi^3ixan5Q`9v>>EAtg8c4i?B_pw5s3 z%Ih5qpO&jtwe>TF4m$Pmy5W3FaDL7X=ZLx>oc(MMw9CnG2G3qWB}um07c0}n5wAZB zr;=NHyd-JiQ2_mN_9!-#z;LLDNg0ay#}%yubwu!#ce-i)*O7-UfN5cG8Tg{^Xwqia z4z%$b(k3v+Htm_jA)%rU8k$9>zp3V{TCKL)*8Z&tzA7k^pQ=$iN!micjOwkj@Vq9tkun@!ZOTXy7c66#PQZAb{ON9Y z?S4v*gFn$ZnGT=ULGWN?tUMd{Eah_qUy>k;p=u22CHWdG)^m&4c9BZo*ktc18n}|Y zc+-YOJPM~$U`YQUs^-3_k;-w#M-}<3S{Zf4$`QB}AjsNqCK9VH%rTYWdf(lBd!BXj z>eCCGP1@+;fnzUO+lx^Z9*LDy&?)BnyLdE_Xw>}+ zwJro@s-Djf7icdF#DHD)UPIqH0B2{;<{uLtZ$B!EkHoprMxyrYas|>K4WPf-#gw}g zS4!)~ThdwvIl>o|$S({k7ZSn*+xk+lU=Zp29hlAb$`BvN?St>BPUQv-*ef8vMNfdT zOD{pmx(Uhc9S@?lMda)7m!fsyK3tz;2&|K|B_is9l%d-QzoHER4t<4FLzc9X&2?vd zI5{}E_tCLZgoGc9n<<@S%CCAhdV;MgAC)Qzgr~TjWB@7qhf!*ntxb_r`+8{-jqzoJ z5~8$P93iFE97t`YQs}CUe_12)+2eW#hCd8(0Kj>cz;6p!_4nw#f~1vdMlGwgk<7WC zsA~?TQB5A`gD4lqP7e4WL&o&PIRX(c_{-M%K$mLxD~B#oC3UdpLWPG}BqG1=O*CEQ zCnt!-hLV!~>}#+@c}Bwm*ciTaP6#8}CwaOSFnm+g{Xz^!^&CJgj5dFr86s=}?_cN$ zqg+p>j0=Cp)jeu9|SaQ6ZuY6xncD@<&mQi zd+O#5rjs+G#4x71(#JQH65Ai@xANz;MQrX^J%0~LD^=Ptavp3E>U&NYf}Onxau2;T z=1_fA#4zAwWTH7JIkfu;ctk0GqV^Y6XSFh_aA@*v8{Oc&*{{9WZcaQ5{cpV`P8kyYg(;mV}^@98{2i+p7E-Gvtf5@kb;oMwX1bh?%BZ;I1Q@Ej4Wg?w+*xZdRfFYvy> zfB9H>8eyKvr&fZgt_GM&x*W+D$fA!T(U+!k8&CDAb$$nqe!%E{Ea+P*e;ybCXl(6{ zk9z5*BIU{E0O9vb=h29lzEk49YG^?W5Fy4kJ^T&HyV4=VXZ53awJ3Fvws4WF>@fMF zG{MBBnjTq4Ql;`*u91_fMSj1~$cUrZ(*g#!U5uzqko*ezbw(5FFSdqsf=xp zJSKX-L?0~v(%Hn*4#FcmJxXN?e_0>0z@TBDKCT61m~zaW#gfOBj*a;|vM$^NX?z7( z^LRTc$vN%89roBY6UjExGpD!qJdX z$F^qDN*g<}vD;6L8`?>(pAJ3$hCY^V;^_=jbbqSz^VNcjH4N#pXW(5-%~SIPr(YY|XT1&DSdk@wojh2LD_jL>lwXZw&3KLTMc z`C4gz9U+=RShdBTo_YsASnAw|N{{6Og9fakbim(ScxH%|SbNMNyNH{#`A02vy^OmZ za}4yNy9BbvR}7x3!_Ciy2?KOENSmtOE61dLX=6mvPzTFb*XR`#KMbp?p%cW;`%N=@ zRhV>BJGm({G=#I>go>)bzvn8aZBSViY_5zGB%dO}gh)!n0{F`&=5j^MN>sQDap%Jp z_Vta1^}Gq$l~lkIJKOoDZhS_RnarJ0!u*VD^7Z_fXp=@IXKd93*TN{RVd_Tge3zq) z;PrblDD)wMpyz9Xj<3$Bas7bmmv;x7hIZ%FBn%LceyccPX zC{6@cWPK~##`17kRf+Ag>CQ3%GYy>~!kXKr1KC{Vrdz8ofqS{gIxUnV*(kRu8y(9X zKCmN13V{USsc{dapnF~x;klcM`qu52u12NUujLOvA2>J3IfkEnyj?c! zVH}jiy%Yx~a5IrTsWt(Gh|=tm_mvujhql#{w*pkCGA($NHXd7P>}-g;weggGr;jua zHbA0Fnlv7)9PRT-hsp%eoJ;>NZ(n_Oi>8vGB_e3)`M_E#+s*)svox_RV^se|Yusha zBgZz6En}$rRcXn;bWP2Q-v7TFrjX51jxjbj50lPfxyn7%MjTziULcON@1_%txnjVR zXeRP=ZBw$gX7=gp>%Ti>K$Zr~L9j+IC7;dlDyAP)%+!PW12kMA?Ae~v%hn4B3*YoJ z{g>lRRB7WH=rMj~tV(2$t*8B(HOy*{Cw=@QD@ltiVYEkvHsRUOO+sY+R%niMAm%6n z?JrVsXKDt?Gf3d)HG_||A+#FPCSFT873kJ%tjG(VKW{qb*F{@JzzT+WXSiIKUfbj?IO?&Qp&>?z-$PtA|Hs`R z3i^06%4@TmxqT8RJ1d`%VLHLfY&4;Y--M_op`gQ`_{NuPCKx2DEK{%3vJY|7bs

    z&ccQ`Fw?~uOj38@WTfv*gbe&Ves38YJZE~-OHzvZmil6sYJc-h4itgY26_whNaI6zYhJcZUJra zT3k__WpwYmkxC$_+u|l;t8PW(lF^;g6@&5-=;nlz5)t?6g;7>l>`h!{!ZE9hcI3js zjPqy3dFgZVH&HL?MV9QV;KV!cx{?>PG+tN7TO!r1{1qa+!&~?S$rNrXu>02p6n+D{ zj-2%{7jd6$YG|%?R4N9Koxn(=DqmP15EG!az_B8!uC+evN!FH2dBlAEo zdNo+*e`!fIU8OA5G7%!f#lq>oQ`=H&FG@@KG#8h4r{1Dpy+|Bw3QLzkzAn-(Na1eo z8YVf+MO#i}#GJ+le8a$(Ews}zdPKBZlv7yYn{-h33aA|he6r_aLllhac7hKHz(GQyD7?8&Ql(rUe~ zBsjaS%yN1I!Bs zR)mizRO+vRjpT08V}4XE085k*W#2n>-GK1WM$9N_r=Pq)d2+wO6K!&Zt4rB+p6e8! zP^>$N;3#p%HrbGkr948rmGU&ma$icE~m9)k-C4Pj4$TId6bLHWsagStE;;Gwe*6F zGvq{6fo$rP@rVV{Q4}rBS96UfftE30V91O0UoUh@axcWEY7!oFh(neaI^p2f3;z)= z6TD8CnSR0W;dr?CQ(FT%8MxHZ0Tuso*ni!r0rv0G1O<10=uIsHYQGV&mPY40-T446 zV;3M}na0tBDf-nk71xfxo8z;t{~Ul6oMll%wNud(>zTq!VVPqf1HH3qrY5|wzVhD= zQWz2#F7IkevV1%$VI$NWS6+_w7<-j%KZ@Ij=eU(|l+=yR$yM%7QEAqQ*o53+252nX zx?S6Stq|h(qti1?>8#+&e*Rj{>!Mhx^Zo|=y(FBVYzBN$%|9I%lH7$RGTuiv^AH;a zaQ3I??Y|nWaoDdKPLTAnSaqg)#+%`rwG1eQ-Hestur-^$V@z0i?ngaVu{ zhmF$zh!;U5-AN=oeX<^j&qVd98QsX$MXFZH*^aC!a1wjax6M4AR?ev-*k=S@@*IW({4m`0B|W1_ zBS7Dw;W~+aUtcG#f~06i!X=hbthq}*FzX;Mrvv9a4T;-)Xmq;YVLi@Tpt6?DIcD{m zsJkJD-pJ}~@v3U{U2Om6* zq|^LR_D_+B6^SRX4!zT3F|GMo#VEuVxOoOo8&t*sMJ-`l6Gxx6-F z#w;)VRavbJgjLgS#LH2`^P|sF=KyG*A!J?3XG0BHn{+6iOCF8% zDIDyxZ7KePAto+N7Epqw!&!y$71`n5y8}@F%ABVkQV@LJ5i-Q!g`1#m>_&urXlX3g z)t?i8_V-z@uU2-&45C47ZY8~=zkcl;T~kKPO~U3flK==DeGfoLBgd zt^U|@MLh09AUD8cz(|I_IlbLufA^Y0H9F*+?B!fV?*1 zz?U|RF_jE-t){9=)aU1wzb;+Ei=U&(cyJ)(0$ru4e^M(X;CERowNoT4$>VxLgr#bI zDY#FA57fYQFXsAgt|iw3x&3P1O$DG+2=-w61$e?ehLN-K;ugi_p}`Bi3A!6+5O(Q= zsUr84vTc=osm)=~%tai2{FnKvoiE9p-MJ@%SYi4$OON_jW2fpYc^4X^|kQI zeloPYXOdkzX2=&5&>ryUdUQ`rS@q6SbUM$WYeW#Mok9e_ZmK9jfT95aalkQ!6v<50 zy~Jggn+8-HU0$mcI_T;`Ukm#I52`_&SYBu94JoJXu_9NpZt^)j$RaO*gy;HA4Z$0p zdjYc4r(;x1X^_Vf)|g{UmPhT}ffVl#DES}`}}AwZnhY z+nlYJ1Ko3SVm}?Cd}!;R@1t{5REu$iGW-`-OikPaq}yg`YJ=-&M@<7Rtd3RYa@Zxz zfuHz1(Qxl6$P= zd%vMC6ncltRBSfDw=BW_Amu($FAGu9RAXq2-gl=$IAMWxHgh7dG*tYS%q~D=Q3g|a zW0Xi%7X(k{GCKsF%~sXPUjBU|8Gs8*QzmA{F37HF$FyE6cveMT;%@lmnYu1c%0wrl zxlU0MjdB^|CM_WU#%E`t;tB-6`S?Dz*y(uU)brd6n+`h{$UXl}_77|{{V4(sIPR185@6}Zvx;#mU;{x>- zd^O3O-ua6Tup;Xz-xFHt1qEuz&}j4O`T)D6xu~PJe7B_4dVIgrK~V7C#OaWz9~->( zsym{?LyK?P)2mj~l$^wjt{HfBn%$*|ujOT8k(}7PcwPxK`+q$!CrgioP|}cd(@F9( zr;r!6z3}9?j8J&~_`%wdCd+()D(h!bCrF`8q%+Y^*P17DAi_Q z<^J3N%PMY9J@$*{02_Re+b)ysg=Iw1Pkz?L*ek<>Znt-8J6+#Fl8~%f&O$SsycPmz znp{N(YlOtrXC~T$ z4>g=i$77I8@o}EF&f5HV7C^A5S^m3KLrae|1FMm@-r1DX)HGMDP;lFFfycY0ZxP zmA7ykS&l$*Qky*nHzVbKKnU5NL4c5%&aYTwNl5>ko9u7Y)TCB^MdeQ!3hbWp-5|aH z&c>V~14y$Yn8G=1qtaojzdTVT@KgwV%3bmwtaTfv#MjhJ&!u4f{~smfh!$Bf8@CM7 zl5BomhG5dK;#FyxXEANJAzom=kik~KY{FjXFDZBF=!wgIBXVWCtTSch;&295elddY z+{-T03#)OnJ?rN@Cm^N=ZRgA!!4vban_v%$apXPQ@vJtzk0lnem_~^o$Bg=C! zAl(W^5`b0Fk%;<^$vk>HFE--kt}|6VMn(!A6WZI}Y4=MOf@fZKCC9(|nSqQw6i}MJ zEW@QXwuy#2LQ$WdCm#vZ0BCxntn%Z+n<)*5LJbj;x63fDg}PY&?;jK(2oCjuC$Q8B zuorG}SVTFVZ=}6n`~OR&)oh8vz@XH0F(J^s3U%ke#oqP!C_Rb{ncD#+otLy61-`vi zVXLTkiC@0zEdw$UQ0n5J0;$zit&sD*vc}`^;4GNkVSxxO^pJVeiFO2=2z43(9*;IH zux$14jcZFueve=`O##C)_|q(pw6_ho+e>L)`1R*MGG>%e{>Q&a>3(E^m)224HR7g# z8qg$EqbC#ka!C_u?KIv9{D=5jW?U~j2=Qqbd8+?#R=%xqKzEs;qtXm+;o(yLq2YM2 zp(Vbk37yDk6|fw>m_{DHD0ohU+ei2F$fV>TY)|a0(OPckS)BTwPC_GhUq=%dJ)u&C zjKKy=SvQq0RL&X#_vWlkrZdc>+A)ykmo-v!I=J;GSkT}mARuHXKa}Wj>m$oUM)M|2 zg4lz3o{$Si{%4Uro#v;6-dkn{c(vA$+0|9}$*Zm9`ID(S9xx|=je(X|#CP=1?gMAT zz(I1~hS{MhP=^(84~n(Lj(6{7XY8Kn8cX9BUM>Y`H_Npbg+syq2n*SbQSka(4_Lwx z(C9}*<$)yIng3Apobb)3`elnarQ89BJ-->Xh=+d$obr7!KHWD$Q;O+uuPLJ0Q^7hsoW1rV^`vKvfnd{J2@3+Nb;u8tCjz#7youJWVT}_=Xy6a}QsS506 zB?lqg;;NJ}!Wr&6?Gc~Z3P3Ok4*^ZKQM&GK=-d2PUE`kQ*8=2z85kuh*Ui(+`7&q@ zh0%Hn@x`v~_m&u8K{aE8}8!GVl{GG^PmwG8DjrUQU~DZ|J!Fg zYaYiit9I{|#t;RPK3&Wlwg4D#{W*!oyhJt|yqA_klK)xC^fWXMW)86>MyIO}{TWV5 zG1gbA6^CVx0EKc$O4%e%IxYS%o9?End-y>6)G8dl0lM(ydu4|t84ym3(VjRRfF8*s zff%+=bet24pw@*|IoCq1-x&NwRko4B=5y z0tzKj!cWDa>LlJ`v){U_4Zc%HNz%cgJE-az;Q=i-5+pOJu84R5l)NZGW^O)<%7rkUc5=AZ zG&exFYGRgXP7Brh-Dxn*WfSulGw@3M%Jtgsbky@FQ)?pP(_qXkY;9|xgI=4e0zQ@j zRglwxU}CNy4i&0garN`yw3zoU*{0$FKGB*E=bGyBwR|!l1oMO^oBF(u2x?44`QhW< z;5OqrB78?eF@U3xx)r#2n)Fxoh@crHVVcZkWsmSAsJ))LJs!rU@+;6z&7jt__(u-I zb3r2EU+I_VXr9VT;qKTuW0#K`(C>R~nZq-124lzTt2u5o6vCtyS*tsqp21B53` zxc8;Z2}U!*{dAq%h}y-MiIJ)zE{+mBH_tl8d`L{gD0jvUu<)b6y-geDI`XN_j6X_@ zCfGs$x~qd6B|1kAOauFBTsb zwcjS9iywG@8aC1P*lE}xAa`b}i`LrpqIKGQ3cvZAQQY#$rb=FWuj`hX$1ju32xgN6 zgAet2sL0yfSrG=hz$%u*t_`%`ihPR1`$HU9r*lzfhBCh(=KyX@^2=Oh`3D2U#D)bM&a zh=nOv@cumw3kaWpFR&s%UDVFqCBHjiep2jkT&oStwERpdsjTBg;y&|3t*+1DPCGxo zJIm=K34RqfgU-D}@Qf21K`L#;)vifUNyFw`?1@Vw|8NL@0>ADV50E~h*%qMKSUreI zegy{=r^q>2}?_4#-)uGjR%P}HviRyjQB-JAH^98Xc)KmVksC@8h*u=UvV zq`nW$TC+vrKR5#>a39Xq7BJ_QhYlf{o7vLho`vO`v|{<#K4doUV8}9LUg-TLs86Bf zPr3ioLw%Tk6C+P=?@D8f1ZJ28->_7%SNVc{d1=cYC!&-~&f}Q(TT{GugSZTODLGTL z$SF`tDo{Y;vbQ_XcJ9iEeZ!DHsl{1Dfki@Lk=oc&KYw_3vbFYMn{;=VHL80L54`9` zrx;&-hYxXqL>Gt&p9xfw0Nj}JQZ1CUM-s{~iO0w>zijp6iHJ&{li&4RmwS?XTayVM z{n}q)J=i}%rr$Q+i~vKm@)zkne43Bwi$o+Ewt+NDY@Awc+Dm;9kTAZn}c+yVTN-hDcBI=4~zoN1a1} zEL+td?uwRNF?3uTn>gED6pLGMjizvEMK^~N=BTFX0nWQ86E;|_MXQyLSS^LX>yraQ+xVzyRo6iSi-S#{w7SdL?yj zQ=#^g$BQ|3;rxA>ufq5ixsrBAq0ys1JQqU4_BYuWVIcbuor&SZCQOsCU|c3+O#Ebh zQullQFc#kL zUs3v9Y8*^zY1&mwxY8ke{fJ}Qb;7nlr{;d27|=g;;j91<*zEJ|Gb&w4D3=%(Dv+M! zF9p@uzb{tV_fkgH44`uQP@%Z)_N)578SUT_v4fym4m2lhXsL^+-|=9sKTje(0M37a z^e?)Z&Ls0)bIJ%C+$ct4uAKCoQ5(QCm>#6b04HG3>73@ytui{GyA=bh3nI=M`T;L^ zlp=_I6<27$v}I%oAhhwuCMrx|eD?cx6hP>weY&!1z)%Xr;{5 z;5Z7$V^OQ_;blLo@^9pV+Qe@>N!I?3sB!GOaf`>!{b3$DDLWXZ{1V|vCiQocGCrPV zN7nx+(kAt0kPXmJ#~IMF=bngBl8rZneye@YWukHdP(fF1vgu{MEdlu?kBSv>CVUjLlxiEo!lYQ_{7 zc$aEm6A{jnlVmu4Jgk*^)n;FKICJx9w=A3z${#~kX`*Y!8R{0}1kJkfyQO>ZWH>@X zO#_v=tH^8Z{wJWGvFF0Dhz7`~cc%Q(VQE*CXYP>sM8J~~gv?QCly5AaMKZ-4bBubF zc0S;^NLW!__T+&@y!szCvRgyOB9Tq~lplvdKs4IfD<-bWN*v?g9CKIr=-mTupJK4T_JWmo zS{az~YYK+lIcjBSAbKL~$d#1M3bculfN7g7lGeLQ(A0T*lY`!CtX5}OAOV#tC$X1t6Kr7!236q`f z_G(!{`6`<|A1u1HDw;5vyVe+U>DH1~!V-d#+>XdFW(9B(ge0He*8PY|A`s|9yl{MX z{j@{}rIRBE7G7GROZ+NE zpC%}9L*Qx#iX3u(sHNgTi|C9CJ~#6+f6v>2UxVv4r2+Th{$`jt0sNwvc+ui%L+v_C zMOUx4F^>Ryh|aLm-jAWoVm2GOm5bMJvLF!q{)>YWT+y z8E1VP04nfuqhGoP#jBQ$HvC6|D>vG%Xu#Uo^9ZL12|bXl=nGZoS|IGgHV7P>2l5%2hc<3xL*!8@w6DRf9o&Uw~%40A=Ldfsh}Q+mW}ZS1>>_k6TDMEhshmNBmi z14h@?3C;?O`MEN-=)MnhQc(o z`$$btbQ}uyK}4XvH(y!USQ%DcA+>bPDNyK^QVjq>jtr`<7_AzFwH9BoJu)1CfqGpd z53`=&IZ{t4uQn?JmcD6+i}XldA(M1tPicuGn@`QC4Wv8VdX&!>vR`2u5y}E(P17-S zbtnhrF+}CG+mYLw?&6UeBp|z!4JV((o?0FpDh5eoVDrrF0yA((Iec}-ilIYmabgfM z!7s=y;88olM?j#5+;yb1-degJ=R>ZcWNj>^NC@|W1ba6=NRi}!5yJkufw1u0#4mGY zjG#At|GjVY;)Nw{Z(uySmqx_e^5YkP>pH|$1620g8LnrAdscSn*!&L z8c4QWo@wd-T>O>f!2b{+amT6mD~(&DBNhlOw)B?OO|m*|Ix)hE&>MGKL~4NfEb8e zUu%-SVc_&67Q=oExV7)wuHb+2jQ(kNlgn%Ek2-_ke6c`C(mKfmt@o@ zqx27$Th2K~K@k&?Xx4Kv*a|zWcm!&K{KIu7(tFteiKf7|_8M<-&`oPyGyV#^gfLn7 zVKq^SE-a!K#B67LRASBT8JfagqC_O;1kF|J!uZ#II;)D@Ea1kx*eyIa?SZ~d9XzVlM{sh zc6_m{B$BQFy;SOgPLIfHk_=qk8yIzAcolC$bQSquUmL91zkbFaEfO8ZRtrCYTAbeM z{eBPqh&=YiU=!N(JafU7dhY-YjmN~MTC;W3@*ZV;w22T6oQSIi`l;wcbM`Afga|gO zj+BRK|K2BsIG#1}VB!QEzk<>~`gn5X!LM3y-C9F<1pVb|<@9bs&f>sVu>XF&DUrGMw28St2B#20TG~>n0`S%1%~-snq0ppWje`HZ5@Aru(Yh&3P@{QDK@!Ns0be{4=FLYqEvSpzc|3sUIv3@GEXXD^>c)HvDdGr&+P^;9vrkB#1r-_?mlL%dl&lv`R?)lXvRg`e%Vp> z9IuK&?%_Ns#@rMOi6JZfh3nAkszCM*VYV#orwjM^_XK#1!e*N^^JtbrfsJ2quww`A zOIRr_Ro4X30JZg5SS7Z68$ zXxGs6&exkc-s^S|>h<^K^8tH*Oz2j*oBatxLM{B5Z+R-BT%X6X?ftc0No)Eu!PybE~-NAw7H49A>iq zazK3%2&@+W)r|?Hkg|DcW^^;Wa418kkx_m^Cy*46lybuU)(>AL>M}m&EjpFl(MB_1 z+a}c+!y4)gB)F~eAaSTjP2F6orQ7HejiPo4phLAQO(1}>^8kX}0c1(0uYQ-IcqmN3 zKrf}hdEANNe4e9->7yfquBv4Bz=tE!pIA=Jd6HXT%lRHAb?TJIZ%+*QOXEE~fMU4E zr5|94u!?bV2XE1x+pIeSAQKz>TZAPerSOV=>~8>cSyNVOG|X?4W3C~>n`?*Etv%)7 zwD`kLBo(-W`7~Ta%RSD}SHgxfH z#a{b_E{7C|?I=L6qHcv-XOHZrmaDvP^#y=GlGTNjND7d)T4o=;rd~>(DsQVLUPo=O zkpuxQ%nrJUnFzMURAqXuEqywKzBtq-S+Q-06mCo1OtN9Aks(4i2Qe1ggZ!TX{vvAb zr~(qklN-^?$E8VOEA4;={)pA)l1wvT}=`?Nn*fyE1I@bf#i?Z^E~%fl2*!>()x&5EX{x%Lz> zcct!LpSymWT*=f)aV1bSzI>u`2fW#= zd(jbKdUbZ!jlioi#mq%9p%{n@WA_Q@Pg?8+F@jV{NAYO%JF$S!0kIUBo2f1{KK;7! zgJX5twnIkH)O_&MWt)>$$nwHbf!kVi>nZ8xVDGV!Z>tvy270ZKMx-uFe)xe(E<)gZ!pdVf`Tz_U6%o*p<5uacA#F$ z^Hf&qYh{SfldCroU1unnh~o~k<#NC6oYRf&?#;Mc$!ZtT_IC~Uya4>C{jXE(dIgqPY7sh98KV1CK6{=A zdD)iCV@o`>HMmq0vZe5>GD4`fq#AB`W#A$3@S{i;=O(3ezz-bF&tNh_inH?Rfx@Os zR;F(!6(Pgm+^D<;ubkfP^I(S<6Cmo}91k*;AVB-gD3>s$KL}AJXnc-D3EM{8UxN%> zJp}cHyp2?Et24Lbb4hZ9mKZeXL$QEZ$MH^TwaCXc0#18wAcj=q-W8`XTK&Ib&QUa2 zJ<((|xf7$TUAv)h+`_b?_z_NF)&tUt8TDT+c2%O@bP_5)1l1zE31$IyVC}&9_w)K& z^674TPE{Oz_xj$%tPEg`L5oD#v@KSEEXk8Jlw`W|((~{Mxy}e`s@p@!vEYqBE?)Oo zBsVc)|Cu-#=jle9wlo|CUlmnul8h>2X`NllGm^AR#=hlScpL48txp{Q_}ukzw0;}d zYjq9RWflx=GX@wen;j-D;GNAi1|IR&LbhCpNY9&numYq)D&Ju&%Cjpb^NyU)6zcy( zL)-+%gu0>TZ%Hr-)Bv?IyWyc}PSCxZ1su#iI<>W&c$e%E91&H(6uegLEI-$!;gidq zr+*XOPj82ly9WWc1g;~`loMM4I^Vm}L4XW^Kgpk!C?R8hX}KtgtW&p6z+uu*Bb>8Y zt3{FcL@6F=x6kK{ho#WDKFhv5aaYB`jrfo^7?wa#=XSbFQW012hTHn4(`>z!CbowYBMy{H8Du znHB9T>+rR@EdNWv3LhqFy4Xl6>d~{&H*eQg+p{Wcl*?`XveWg4%a~s*Oq2);C@5Tk zT7LCKw_$-5oG)Q%C762XL1Q}(`ou6`Ll|qVwo`MQoocaZKg{kfI9U#x$?b%$+ZId- z9{b8qGm{VmgZwoAEFis44H6hed$sDPXhP}Dk})scaD{jYSsd4(g)a$P+BK_=K1{Tk z(v_k`eLm8x*S8kN+7!M}`$@Ll=t7m@=@D^%<26^LvGbo61{*VPugYKM-cyQ3vt|N^ z$VWIZErIbixcegHW@#=jVhk~BV9BLUQ}ZXn4#3hQCnJB>(jnBEK0=vpRc z7p$h3)>P$y5xflA@_@xT++x(FTx{ZZjcf%K*Y8hsG6>5KNXXwJ{I!C_F9`J08M>Xm$YNFvq3~5Yi2HB z7`6;j%?PBoZI|fLC)#TgBQ9MZ4Ly8jZZLy<9hU0+hvv>Su5CqzRUTF9A*MOr159U!{t73W^wR0|BP7arWZVstw~u+gaAYN}&EjU1HmEt}QC!If}jh&zl8y zC*yO903vt`NyC-N0_*U&d3J?P-u&%<7nFIOq@`g8T~JxjY0S&ZZvFd22Z$6b*xRVHh9^(s;`tA znN(yLozAe11eG7$kw2%Bj%ZJ!iITKc8j*UYrd1;hXsen>`$M!8KDds2(C`Gf);o7{ zwF;FGi+a_UJJM*pdQ1<=sC@j)&7c?js(h7#@;5Z5PM!GdNy%9;KAX}Hg1x4w{!2k~ zP@*zDkGjc5YipNhnsSwrWN<4)pS5K zI^IFs*u5!d_#4k^B)^wW_*@!H_f5EB+s8kYA@VH>L~mcgFIB)^xMl2UhfxZ( z=|5L5lfmMz``PBnLq7fR>q*E2{`wHe*Rxs->t8L70D5L7(w_0;Eyq66eq34kVT5&fb=BSMGRK_Vcd0<-)=yMBVt;Vin z6P(_Fi%UYKbVDhm%(rj<(Z)r{S}R{O4p}|r4-V^9&PbtEi(v82BQ~2k1$3bd%wO~G z`atC{A!m8wZ$hyeRqA;4#RwUPSKv)_IhglQzB=*3yKLHsxf>wJy=dsGaD1X`$TQ1? zqRJX}PPwU@gSB^lxtK^kOTctzy`MgY9Obf!Da1FwabKk&gLw18 zneE93L3NuczV6uJ>WIDI&*G(YVwxon`YVBTGT>=ra6#6+r;HXuT^$qDg@#;|2d{{u z9@f3Mk3t?%uTVs?aLA0k^E&d#sxt6IqvuNCBnfR!#kqCc&9>)bOO?-C4{%8P+nd+% z^%QID_n|D|XCV}%^+=c3#g`7`Tgv|G|3TPOi6cq@DrjQxF|P3b+!U$rO$u`Hu`RsX zgMEnO5Am=}{PC(YF#g&o+}M8=uYE--p<7gcCz&&2|mxWM|<3TAF}k>zYP z$StzcdPOb*8~QR^QLgPwTg(UpJDZg2)JGu*tTO(BQNQHFrODZZF}FlY)7@@M_J@i< zCzl;Y`Io`Sj{opl*D77q|9D%Gb`vRyOvwgMa&Z5T!{&Qng&vjPe!bklk(nebwJ?vl zHa&#{SR{daB9dl{4K^Gz)1q40ZW;p=`=obF5H5P{3~g4v>jj6;jX$ki$n?v2g2QYP z*&+t0RB(Jdu*^kj{Z{qKsZ89;BkpH2f^t=Wp&t~N?SE0wix%#2D*Y9|a}%K%rN_{# z7WeGa4Lz0n12dTe#=QCT1I3h=t6Is@(t>jS8!Q)&b~x&1TViYD@%FrCq0koS+DKy# zkMBp05h)O+6yCIwB2Z7in3r^U%IxoMzDkW3`m~I}MgALYVY{?Xl8F>N6g(~&ZR^Is z18;psbS-n%RNdd&lZ^fI1`=JsFD7}mP6sWH&2}a&44n*w$My&NArz)R9m?fu+z+^^ z0AdU$jO>#9SFFv8vuERdiN2>jGzTiAGup5O6&WW8ET_1R$+Ecj_WA#Wr@J47tXe$RrJXmUT;cxLUlwcrnQzA= zG|XXsPq-PZ8w_okug|1MvuE+b@D{3LtcPY(1wKfXT6l|6iVdiz=e2r?lt3yrC<$}s zfW0(Yut2D~CJs{uFSFu~pN;Tk^PZeYydL^nYOUC~Bew1^+01V!^yuK0ntY{?I}f&* zJDNnRX0q$q7X&zheH3)L4VtPD#gImdojrOCx;|$L3$b`hw=rQnnN{DR1_DwX0+!4! z@!qaewI5yrN1#NXBVa|3yc{JLe%x>bRm(J0v1IaIxY_P)?BAi;M_w>4IS+t1Zk7$z zun|HVYJxQ=)usM{{Pd*fv?^Q9`k1N^)=4MOnTFp#-w!ONr<#U^&Q~qA1fNcphu|*J zvj{9Z8_hUCw-jyrQ-;b=V@z3`xNUhqbz~4yC*Uvz8e*dZUx;Vo8@OzE7lK+(6mbq= zcBfGo3+5;q&FjEV`<|5($!N? zEqag_V5W*?-3SohXWZ4iFWVSSEXo{%s;X=IDN!)b;Mxz3B{Op`6CSBv3TayeNWaY}bCzv~)I#-l zULM#)Lz4;iDf@^KUJTOesK<((|2P)hRi>NxCS*KR@3)AhU(CV#DsKaOzmPBE$l2e*c|((=m1i{>##7dhIP#CnkV;p@y-jk zJRh&rX$%4^m63e-Fj@ZHn@59GABWcvKu+0qb!0|y z2Q5IWTO1j~X4kAm7#7c3>hP(1;*T8b>{F8H z4dROz4e9gl#SrR1J-;fTb{mb$pE%SRZa(XZ17?^IvKsa~&m~>_SowHO8Lm?ROFfH5 z5Z8#1h(|OGJ{LtqR~JHolHx(m_yD__lO66%he{(MuK8tuV%C6#>16}>&&98MAc z%f$;On_~a+KoD;W7`X5TPG*m82)dsL9(8(J$CLj7oN^m%)=`5 zM#8xj4E$J9li+rK`mYoVboMc4NP5osQPMSXRy6viwCFT{bAzBS(aXVI> zw{b5ay%Q*Mxqg{(ldTMazB`v2_>&+9@CtD07Ws@03C~LzH28N3YdhGP62dxqLL&40 z1nm#t7`hhJ@VxMx(5HJ7tYDi&_T2!bKKZ#^j#S*?iD4>+Y^~(0|3 z5k1sG%>I%u+^=+&2(6A}k!7txVkh{B(vtraW`BbX^HiY&f@^@(Gi@es`Y6w37=V{gRhwo_=4tl`-hiBN#etOkmG<{&$b zL&`|xi6RJD%Hw7By){0f*W1kX(CL+h0A04e^%<5^L89NJYk<{(D%32rvw&j?C!TT*7%34qfzR$8(hc}=`D)KOwhuvOloGKih#l>jr3rGW}m z=f0?9ZSLg67s~?3q%r9v<7ma|H9&iM=b&@=-$^_RM(-8n4BcBR**t@pzr-p}8`@ea z@SD-jU4{j~qEu;Re@hf%u_3^KLk{2ah*%Cl!5~vGaerEXeamtv5-h0esAhd}C2)G7 zG^a#ZpX4Z@tFhTxcHwA^l6aK$eSDs_q?a^e$Z7fs&d6t%y0k(bz3_P)(;2IU3;Vo1 zJgxwcyzPEBww%p2>9vvvKGi`Pbw60Z1f~PHilsrf+4L0(t|lKpL7_q~7%(*0z0QsU zAn>VwsK3GVc~+kN*7UM976M!f>CK~LF9~x5PowV=OU-NH%*AtvdA07(N{6fbqhS29 zn_4D=pR)Qek3NlIm=4N&Ea}7KBm9Q~0WQJX8qQSZMD)}0lF!A{IAx=?Ri)QCaj~yp z!v0Q;l=7srfSbp#z0EsCRg3U(9?Sfsg)Sx*L}>d)Nr{?C4xiWSGym!}Z{yyzp*taf zPG@*Y?OyTMcv^h@vZ2fcS~{DB?(yw^Dh-o}gYU0w=zUIpU7_P9e-l=3{4jr`BH|Xx zDpJjcXt(XVMOxB)9AP09Cc8&qn)NM@g z>5WuIHa*p!6#XiZ6sQ9OnJLy23oMgaD5*97o-eXnOe``&y^Vki+Uu$bb3G5<`dd!f#Im; zxHgk3kqpJsYtQ*Qi94WcrW7A|#1918|6PsT)eHt$w~# zDl6jDW@U)L_LdS-c7%~(iM;jjHHxtBs2U*|V8wqzhr!?U_X2FnV`w~r{K;|X!+?+Gwz4M8Vo>vcqx@j! z`Y<5bJ#XaYk8jcxzsBjxm9rl|c@nIZQ$@RnAl#U!L8e|+hyst0vdGJu= zBwpSJ;ll!m#?Xss>?IVh^{Z>C`Mpp@qkaCl&}P!(5}pyYB{EiNqOy@MpNlu)Z%Wrg zR|tF=Kd3b8V`Kd6Zeur;?kI)Sc@R5wiW_maF%WOQ32fUF+2GgaSB^t_S7sh$>tlcU z6j|U)`CFcdimyC4M&SHYU5s}=Wz7bCz80s&=&kyxN|VMiJR4*T73aB^;)1~T0Bd8% zUC&~i<^1^$gww6Lz1u%g&(vdIbVC2dAPFmuEIi&)2laTY(^^OC(z2!m&~zY_DsYSb zM|I^->0#9qb2t5CAN+v;b=_jS7*=7nZLw>Vx2V4BMC4E+bm7pQVQ>1Nx=+RrlGh6y z&Mc=a$0MG5nqpftU(t6sQ@x;R2e$dE{dk#P*7h`#nwo>%$IFO+?4x(G2HCgeyq7W5 zj}dw?n#wUgVV3o;V$4jtKTuuaWK?k??%G+k4t&6rrwLDyvbWh7y0|k@UH8t4^m7cr z%6EBC;omQ;I{|+kLD>#%D!v8{1NXLa3zF(3UjW48rdb1TZCPAnrAS=~>|lLK>p`M6 zs6I7Se^G*^(hJRcyyNX^JTz8`J?0U`y#uK*+oyd7eC>Bm6hiAvmatm31Nae{t+1Y( za(CSIs-$b51+Vwg#k`4O_0H+)9=}HzOLn+zL#x7ua}ZvqZFwa!>?bnxk!Vt5k-7x@ zMqbnGJb0vf{#m^?9AP>ly$NkLOkJs~`36oJ=vCa+U*dT`iXz$#?yJIGU0tISov~8` z@vlzRI~R=Aw2sM_#3WBRH(l!~llCUVFmDIG@W(dPZYeI61oefRi?Vbe(`l z4tx%6g{|_H7y6HTzO4ho?ty&{4E$5DAw-(?^HM%Q9E~h^99*k!`FzIsd!Oda=+bsOTwMm21iXHWN0j`pn7 z*G&4;NWaM%rlfOqR$m&AivBv9#rNVlFCFC)b8ngc(qOJtvcUizuu*=OY zGN(9g|G;L5`D^JIY})HfsdL=LRJartC8mEu*oLpwv#V4JYOL0 z>!Fic@&e$NLSvZp_ahlbYY=RzD?SYJx%Iwsms_Gbu z9JwOQ{c~F2Zo}=Y73u1}wZrL64Wx(^%v5rqD}3e2*?brK)yR_oB!%OF*F8o>fg?TO zKM5vFbeVDe{;y&nhi^{66nLSUJk^y8NnFBsJ=*d)+>jZ7pUrc$8se6>HZjHUuyBVg zDCkRZ6V*A{S-e_8K!TbUZ1YqyvwWn6o5l8ccTv@`;VHvjF9ypvW(-4rZYbE25=Qd_ zQW*lZAFdT<{Qn6IodND3cYc)ULkcnv%fA#wjUQDH;(y?t={2(s?8&JnLJ6cYWfLsa zjb1~PM|E)_xhn*_rdO>X91udWItW`P^bC6t{iDag&W%FQ2_emJQ?kpZ=_Po;@lgg| zpob!*FU3EdbhF}vTyqM}n+DI373o znzMGJCD5rf66FCcI(Gr%kJyNc`dVb3C}lm6MT%#pE&a!2L+5!BK1omGxVWKnCv@j8 znO`Q0xaAppY9s@%5y2GCSozDHnCm0HO@G5Uu=eAa^39sf?u&FrH@qf~T}O6=MVVt1 z6f4}8yrcYdi(hBSE)&B8cUFtv9r7%Nw4@!jN$_<{5(P}Cd66@Oec9>l@!@8?eTS-! z_NmFm?lLE_N%<+>BW*;ghcdjs@hJZ11NgehZ5PA3ZTJAU^SiA>7Xq&~5K6E&qBkIV zcqeM!R$#3`!^7cdG*-w@jIPG(vM5~5vz#5wlL7R}MvejymmnK-2$bq2q4F4`C`owa zw5$tWgkD?2?>{K|8A4#8BPTd909sWOJswmhC{S03rps+2;9RFoe4agr=#P7RW*K2u z@ddZ~=#*jke#TIXo=)b(B-P-}lcAAKx9Pid6C5PnigG3lh9LYFmHp@fMTr<-@>=>wwl_ zh0SV%KP(~Wr|@vC&)WHhRGYx1$;O6_m#r6z9K43q!I*3Bq!Gj};g{4wmK3)TS`t*L{OpO^pX%RS(#gJaFeDF5 zez5~nFt$NE`-N1RTv_E}h&S_Ft*-fX3Ug`N-&?=YqS_})&BlZhhj>J5w&Ec^J>Z{F z(#JB)D=F0%e;z67aI9K>>rRw9=rb>AyC%fLavq=;D3WV%NL9FnkM zVox$NYv(GY(R4k%d=<;*wNr=6)%5l?wJkev`G}Hbsu~NE*d8-X0YHIU@iZDtEQ@|B zUc5}=2X_Rs_2P^R!t4>QVUk@p9j9xU;Wk4RCs?=0`iz(H12GT;t4NC|7VcQ_K~nmx z@(}AQ2>ijp{NKlKrxW4MBjfCE{#6lh_eGTPfbG>rv*MWaHLe>cVZONFa;iQkdoOY+aQH0NxmCx;rmq0i8({ndk{KmI2BA8?Z z!X~=;+v$htKn9vS3xXR-kjyUILtamNNjuwTG&4hmA2BN%J6dZZf5oi-IPOd2$E}6| zyHFTW$nXp@i_JKc+Ji?QiKfJ3LJrfsD~X53k58F)dvIuhxeU;dm|yVo84#eehC&MJ zr|o3udG7ggElpkW2uEX2C*c**iE*K)d+ScZ?FG|Rt4pouAO5`NK`OA?2mkx(*jaRi zOv_r$Qh!Isnmy@wZ)FY^+X~{X9Ast@%lZL}cm_>s)wlT)owt*MTu;znfMRKSp{M{-b3I3HvxJQt#^robMt8khA#0HL0%a z8FcGQyrm=PZqE|Ra8lAdjd9CnYs)2AKZgO?X;1wb%&47O*0>vn`d#tNRxM`b3L{o7 znc|X|ml;B^39*=q&ETO7BTxK{L3nbrSR=9D!AQjB!jMCrBtJ1zT-z+U%;fT&*dotb zqTi^1kcR%e$68(h9{~<>c?;Ql20$m_lH8<*3r!Y4DH_h$*soVbBS%|X*$-R#cm z9bquB*^qod*iMn)V;@4^&zk`E4P2Ly(otl=~PPv!@rOc!nd{!TJxFPhqeO?l>uoE<=o8G@0(ys|V7 z4Kc3(Z|1{{x@gpnX4PqrKQbzviV>g`mH6oB_ItNNcPnHSvpD!_^7BKNU|ZreD#L?x z+R-q683%Hl2&S&L0vM~u@XJT-kWUqR57m~b=&geYBFquT!R1twdi*2OOQMfje{&AS zSM)Bv4|~o7iiuWN3Ev0)T35&L$^7-A3i@VArV7<~>d&1YYM5G>zRj;Qt5dW4^dNax zr~K86ST?KC;TQmvjIuDupqZx=%yhRlhnk-CIzzr}r$+^yGYkcYRgB47e9Vxz_1MQO z+!b3Wk+tXOtg(xxcFVy#YoWH<$7PVz1OtxM?(V`9CeF9WX`8(sW3u)F$Zaz3*$=CU zy2>AHv;igk=AyyW*jtk3uydRPD#Sq!7H$-50Z|p+i=sCQJVg%r;DbJo#BoIrG(c11 zN@-xuG@#`?wFQ=wL^@_XN_QWRZ=h+u@>}3;WW{cvtdGNYZgn9atuaf1rz)!3f&$F~H z)s$LYeiRXl#p4m3IxEDz~h zQ*Eln5mzbzTJs7T1u=tx$`YR8&zuoc!i22$t}KoL-*Pac15Wx%N&-DFM4I_VY{Siq zvB$;L-$slC6RJDVM^|{UEuDLo9IqPL&*Zfq(Q-@Kj||VC$}Ke-M>ESJ_k7tEV!`Pt zIwlt1JbO@Pe_S0Kj}Fj;b~b2nZtqY@WkKAOH@-v*GNEvJ~$4Az_K`&{n%YU!=|;G4Z3kZ}5b2rz(?yj?o|H_d0V z97i9#PF=%L6C$W?WAsP!jV=K+!qWMdiWQ+Pg+K_F{X|ym{}s10#D36Y!L*s;E%acf zl~7~!SYGH;{GkP>t-?(bGeE=hSA|rETSb)D4P6BB0KzR7AOKDHv}<$l?ljz~51u)i zjz$MPlHX)V*Rn5dSK-+~Yj))1H-vfN%jF2*Dq?FHpOtSkejncIWV=JXI}J_dzmmp@ zlrTMho5jwQpd%}#p>P469`v260kp4mt|Q-NnfPn>3GFUeQe(J5<{mp-dExxK5>-?flMQuaZZRMF&+Z}IUjH17(3Z=T< zhcaG~6ZWrRn#(}bTnjIp(Usu-MV36Z95(Qss}sNP#i$sq+Rn@73+XRn$(UC_dWZmD zRsRbbx?0KB7_|nanAge_P_*u7;OOv%F*>8;QQOZwUWHm?KHzoOOVA#YfWrKkjWUTD zpavzcx5Msz$UvsyN&gj1m+ofAbAeUigTt9kW1|3_T&>dk?lL-D(9KFgp5bPmO?Wqs zp`ucFZG^0hBEE33qnWgCLg_+tv#dD)eGG>y)xYshQCL2wdwMVfka6J9;OYvl?7=gF zbW!-?riPeJRF(niG4!|{!rgQ7rTc!*@C5>giNxKcm=MDV4&R=K;`a13v})UQvGsgc z8#{FRU8ctXi3c7c566+ZxLv|>Bx7UV`J_gLl_nQ;>qor%-?P+2T|Fys{2MA?e~P$YJd=={M$no<$i{P9Q4uldGCCiB^~R9rK8q#O zZlgD(h1Q}>+PPlvSBq+pi8dyq^LsbipXIV4 zuV5nj4?+f7%!dOL?Hf^;`vnQ&2tAWc*yv!bk`0lsNMmzRvM3n7g9S!W-|wxWiG{^ajO*DY&g$?-YX<=&ZSb{R#x3&gO*fa>F!LJq2Rj>CzryCZTsiYA853 z9!o+;E&dAdfz7%MryY60+8q*RA*S2?Qv7cmFu)~tQc*o-^&fiELsEgn!iTn4@;ZTn z>ByywH!dHnV~pt1Y5L*1(8wE3jZG%2&^>ymg^z>}tuG}#O+Oo#z+s)*79=5#EDhzB zNJimmD^$jLHIlUj3?l}KzK9JHq|jRQN1-aoGIyJczFCQg#Kq7=TPb^njxGyzPF`Vi zGgmW^Pa(0iDRQkzqkQ1`9-c;vuMrd=vqC&4>V#V1ez0cO5kxpL?)(>k9}` zX*nIsM+aGMB@n%NYqr?Q4=K)salYRx>cG-evsA9hHawMk# zL|P(-BBC5Auw-NMyrL<6FUKBjU*dA<6Pzv!Kap}CV_$h!$4~(xzjK4K&G1Fg2U=ko zez!ou`!wNAnVccRP0!k;3J~{jV-Rg|s~5Z;zBYlAZ7(7DxfdHcD1;#^GoqJtmW{<= zUJ`vWD|qDP-fn-nU-izi%Wsqhf7#&F z#U*UN4CbR`Iax!L^U_xEZH9-x`3+vD^lKnxj^DunNr8xT#;E2!np~c>%v-9gnI{Py zeL+sF-D^1_VauPHNzZ2)gs>B>FcW&AROw5uOLw4$xrp(IPhEU_hrOoz@k4qD8&@+n z$YTqxR!;b1#YHrn@ny}Pz%!Ohs6<`=^g#ljN35Dk3$r(ly3yDykm0==n~mL2FYxw; zTaT-7)y+yolevhTRfZ^>WkSB=aODkR`Yr)hGYpUWfQp(-G|sa+kka}XX7NFyKQ$=EX@ z_j~V1kHuIsYiaPHTr8L%B?ibMI15!Ody~)xTIB6;`cTJQL!^Hk?^-wpApQdkEtBQj zF+hiRtz7dkaT40H=alrqFB_l-Jrp(kBDsrpzeZeY%RkZnS-ow(kT~5pI(^8k>1dsRc$$`1eDc zI%zbirY~1Vxw+cOa@#!BA;s}8;HVlnC9k`#jo)<%U&2F^TY+dZgqR9ZL}&2h$4X5V zjetpX2^UY8_ABh=tqmrkltY64iYTGiW?Qgrl%#BPjt?#V(HXc=eB_Vm^#gR^D{i(y ztu;Ji1+miW@cFQcdRI6>@HPBh4&OZvYfbXNRuk#)57^XIsR(6OkH(;+wH> zDS@LUd9G)b(t&hW0y~yA2M8}aPh>quyZ2;P=6(keySAvH9V#fK))~NU11xQXr6wzy z0ZYL1dR^{v)A_|wYYY~*h0sFq!oJ`&JFe<}^%i&WT>`+T2(&bsI(eo-LObvDSdoP# z-Y2>ocbV)oEQE&!+q-PKWdWnq1O{TMq8U-Moe6;#9;?6%wMu4-JV91bHT$+vI_68a zI~ll6N>2Vlo-$KBpyA|K-)N)g5hHl`>6q<(oyz3n zS|(1LN0j0kWXri;YS1p+%xo-%Ox!|PBLDq!w-SZ0HM=DM2B&xZ;0)VyvyCRPLz^jd z^8`Q9kmo4Rd0kQ$!iU>%>G=U=_0VHMzdsgz97p~YNhXj4ItbNt;XKlgXegzM7x4tH z%^`O<{{vi`Mz-xVOh}-yP*pkbvIDH`>B4UZd)9EH{Ym=HS_fP0n}@)|)yx`-uybH0 zUo!Y&RcOyFmuy;v`5=uz_?sT){SEw-D&s#8SE(`*0QX}?jKPmjJ~g=pNUsFq%p~VK zI(#eo%!}<$&h^5kDF=X+g;BP}5->Ktu9{t~>XAM1loqUBV~2$xsp9;?_0*%OtINlGN2g)cjE;Vw-2l#)cA-RV06eupxID38S8Ca#DD@$AK}<7VMl=ej z&K+YGFLjqX`?G=-5tX-IR5r{0n(I zsExKNrz>OTQo8X~FEwXP8zK{Hpw==WN1mcXPZZUJsG(OB8(JZ*;?KU3t+}K5^WB)_ zBQ2yJ=gc%mHPx)EHGbo-$t{Xy=A;-y#ONM)B_Oj?+q!B@g3?^-y#;HSjh zqLSuAUDVW66TK@+BBS_6%#lfs*8Oq<>j56ci}b{DdW-m`*0R^?WF+BX&<^sLm-#+P z4pOT}G3HCY;w=kfqZ>n1Talq@DO~>k1|iX^-MW8&WLgK8;_a9Jpus{sZ>@-Q$Bg*H zb0isnWkw+MXFeUn2_cfEnHtFey)g_gx-(QM#b5oo15To}_xbEA$wQdySu8aT3g+t- zV3_monHC^>p|$anTbnM<1BI z#U1ECd#CMFvSQj@>GTd1m+h3U1e&VebhTHkFe(zPCj@1{LkIXT@}uAo=NViWfX^E3 zc&DN_%kT=ifACj|il)e6?F4lCEPTQ5BF;9YfHTff5I3lK^MN-+lUqEpo#F^mrW`)+ zpcY-j4nP zgXhVD4$UyXVSx1=Nb&PUNjj z`Va|m63pE0Kb5Zl;9p+5vYw9$m18UJ_ZwN4?~13isGQ6{DMNU!Tnpx1s`FC43(@Gs zwyeVOC&b>aAFQ7;DyC&(prw}>Ct&a$zSm9)FOqjS`y+6oNg)t)rk(JNrgJ|XVmRcC zno|Q$5?oojZ37i}npe<450Tu+DZ@*l(;29UOe0x+Yo5sR+sL$p;1AbVR}6DS{(lBa zy;1`y7qC=Da|CCA#{F}uChHjqYEAH|3;Fs{|Ies%=;E^>jT;zg>w}73Sqqda0oyYYti$WIFOKxEX})++oRX zqngETT35Cu!GK~Jz0LTf(&1m+tP0SpR|SB0xi3J7v`rEd?*&IyU#0xL;d*cnIB^~b z$$3pejIni1=*l)V@6=)Vt9T3EkBoYxxLp0eQY@?&;MU}w^|1G+f>XoAClSa6tpgg# z1^`jCJ!aqAoRxp>h7K`L0M#uRYSdxE1b$8MVRMS47AX_dHx4z1=IKxCvkZGu$Lb5X zgQR>#(!I8+%fvik^~u@$K^>);hKuU4**FoUUnDAg$iKlz>Ex4qF$0U|^)OL;=HtQ` zb4LLGlQ>58Jv821+_1qH2Sy~*d1d0_3o)cI9L2Mma|O{eWaFA0>8 zua%m|3Lp;!H}SQtqvJ<bUG^^I2rH<5wHIfC-Gqy?VjJxN;5 zGp}z_zvkN{KH`zDLkmIB4^H*EN3Os)C%qRmtO0| zg1Vv+t1DY;41<|d5@Y78A-IPh1ZcB`;h~eQDKIgA{3H~5K_l}T%XJxZrO)M_+=WZ?Xtvt{LO@GN?5 zT2rr{#Z{bs(Ah z3Ep!bugA6~s6&r7tbyhG_BhSNK?zW$PJeB+houCT`U0g-=``s8M3;T0_=R)pa5ek# zb2rVA^#HU@c5M2-H3y8lVa*|;XVVVnEdTLA=2bzr{EJ#Nf6YrYy0^MS^6*W~sZt@( z$!49_>Y)64SxeS_)7Sx+Ue5c%AijFtiuD?-)h%yLP6nPp+8a#{-!*($j#a4$e)a8? z=`7iqBaa856OaRk_qSmh&_00dg`){o8>ZfUF0HWBMN3ca;eedEm5Fg29ZDU9*gE7p ztEf4^9~D*|^jP{pI04CNJspHtbcME%n>o;7Z>JnR2;9~f=)JLZEa*KsLaq^`p)O;Q z{^W9mRmJ@9VL8R51gxy&gvk6ypi$0VtG0e~18H;yy#8Kf`DJOkD1LCS^?dc{lxOl*~~Y7M9d7K2Z=RnqGh z8b!$6Ej?=+2@BaE+7Rg$@@m&XXD;s;KaRk88%qxjU?UF`6o&F=GPrB1yT9Q$#KP>R z4@kDps5pQ+ZB%-@A&#pv;TW2?l*iHq^MS(k>61A-hyK>A88?6B>J{gp=`THj=<*FN zNQf@y>#pZ^=B(6WR0%cMPCuXfD@tRY1Z{`h1=6}6GdjvE>_M_|_`@NXfJ$qk7T+3@ z6lH`<2zXVJ8w`TMAD^Z*QK7U?Ml*pU`*A3R&=tkjR37`b-Y`ku_fU5?%+z?a4l_AP ze54v{^=A(F#rw!_kv@(|W7L-9`MW21tI&bLFUL!#_iZ!_P{ zq@aja&0Q#Jg!w$r=lgNQD?^k8LHMb6Ik0${7ONI^6W*rQg2z6Rc*!0k>I-Bq7C}y@Kg^Cqp8)L{4tnEvsuSoSXo^wd3kpt5&%5#ci^kK z+C&Fduu09<^@OH=qr)MhDXitUKcgd_SpOwKK@N$jU2K;G=IX8@)27O?_3s!Z1f!f9 z(WExpSyf;-;#$(m&zpMf=$2&~gxZbF=tB0TxZiP>h0AQJ((zQ2DBJ3`Zv+RK(7;ps zF!{ByJ5gwGA*F}^pC7Fk`E*Y8PNu*>JG|}sU6Jl91RxMtOW?;QahCXTlm?L8l_w^f z+PmyeH}H2f$QDFv;LiL0*=`W6fUg=b&VG53fQjmp_F z*%IP62L%;1kCW)O_L8n++4upfoTE%=fj2(M|bw@IUpY_!@BxTl`+J>)bfT zbW*Fw&HL5C3JT=0izE49M)xFFudJB}0B6F(3#t3OESJHt8q!7KglSl|!?6o!p}w|2 zVx$+;c5bmZ)k@Ej+|#t;{ZQM+)mjfN^u|<-a(;xm|KEJB;mgNcfvY;WpY+H$YELU1 z7<;{-Q-EMW3FGu2DT6ooihMV~Q(7ZP;s&Q4#rr?)=Xwxa*6ii?p+vC6)^Xtm?TgiR zAtKo7oW3p|Oh6=8qpk8Rh|ACt_nV>$C4Cg!(V)C-q|Eyc1%?&Z30C)KDj)dw1bs5C z_q#xy{(B0+LGR$M%VPnhisEiGTvyGx0oa41UjgpOO#2_{yA;+vMmM(oK&V`)k=K&` zPw+)m#IxVQym^|vGzqLlo$4_CK)Od`2x1TjMupV;E?|f-w!Vp;KVgjV6#ejvNJCD& zLuqbX@viv_O|waz>)&{zG}O@+?C%a^|*A3q+Y^XpD%h*^lfq>evZi2 z#pvziq!0}W0?-A)O39V8IjsP36Z6qhWRaUWr&w^Uli4f6%edK4V@z0CA5IW7@1pZk zt_ywyh&!IyF|U;pQEG8Z)ilqvUKx-FA7*Ywjc6NYiIgWCcFh1L>|$Uk;vNlXc9_U8 zCn!3TZ#ovZ!73H!2c{Eb}E^Z#mmvWmu-b6vW_6gdNe$fZXZ~HEPK}FBu z+%%RAee*1eSWrw~^nTiTtRn>cR}i-$Lz^iEY@Y?SKAF_r0Q7e&0J#28;=%*6dpzdS_T;0>WqtWUJz-t4LHNM$K5)n*JDt?p*!}HUogcoJ)5AnjlLYgZ-{;` zA#i0*Dj@C*APuYLPKy;?V0zo+I(lrWBbTXR+XTeX&?t-6^KEdtzyz0s6-%>z{d_PB&| zoyEy$XXr;{@L>z~wMIKY90fHx8BV6hlAI8OEc(OAJ|66SiUx+Gd8o$FftZar;>#4~ zmbfumsDH>0m3OreMRf+ugK67w9)OjANy$3md=kQc*bk< zDhCH&Q>x3E;*j&MX9S-2BY)P+g}k1CkS{{C842JghLts#zI-`uFcw>k7q@=T>wTJjsHaxs!5NE;MqE6W}4Bp1qu)uf3iN7PS*>^J_X2HG-x$M6L z=gXzVEK4^n127?~0Z6!Y0%pF`9bc$W5SQP~JsRU}KQ4-$&!OO$G`CcS9B*LYSP|0a z7PtciY_pzhT&X>u0hV(=kbj<422~(Z>RgZ!mz&|VL&}DUy0;t8{A?p=94zT=EVtRd4^~rWIQDyIwsSq0GnS zUh(_}s+5+#Dj4WlN;xN)p-5-vH!(3jO0CzUM#?!#!HSxN3Wq)=MwpCOR}vEVI%ie7 zXMqu~tdzRsS#`V^0I8ZM1*ob*ni?61Zr}X8;Kh_PMeYMcHxCS)TA=(xw5%WQj`p5E zZ6>nKcblCAd8uMpZS3OX_oAq&gpRklhxEfNu(eU?IpZ4!<fkbYPT^OmgA3cWpw=g zWPUE%Qbjp)A{{_2evR;fu*KMTL5<(ZA)lgBWnwzYrx-25;b164A#q4-dU6 zP}&zX;wtTin4bXR+>m_D{L7Ns!X@zHz|0*{RXOTG9h_f3f3X52a9Z-@<6f_q&!)p$ z8*~=PeM;l)*+k6dG8s-nHbRL>W0w?fI{RW}GLl8_A>O_=EcCCcbGRK8k%J<;&E}O8 z`UoYS9q3Y)xR##5CbceIXsI49yMZEc6m3&X#eyXCIH}~dDH=G5kM4vDBlCj?m+-1LD};?dwcg(uIt}=?#grgmjy4?lGbgpzhw% z@1(u@es=EDkxT9@l`njOvwv7`S$>bwDn48*<2@d{Ev9%BaIQ$Up{Qd8g}Cxa z&pA>?ql*gz4gr;OimUW4Ub&wnO|m&$CQqSNF_>yx>N2<1xju8 zRoFetk;JE<%K~nz>8PL;<2tR3WXdI2#bqF@E1EIh)gxEvckofl3YP=*u*tx*)krRSQX8 zk7wYwBZe~^WvFZ? z_L12H`tHuhC}pqbFV`#Ua&$7Ir~jfwSb>h7bq^!o2$32 zKT1qeaT+Qopm1BStQqDV`}aet(;BWkZ&8eBjde~(iLcvxVQ`s9#AvO)&%uA0s>?`s z{($NJXm9QLUe0Fq^zczCb-94^C~v#%~9p%M@S+HBOekvFuzlGu#RkO#w5|r;ey)Q9!ad z77SZM?rblMGk)*Wn(UCnO$;0k+6`XoV0Su~5YL0OAjQLX+|nG{^Yx%eJz zek3*4EF)u*19EmZM{8Xb-4{yHz}${E8o?_Qhgc*rBzd~CV&|wP*hJ6WWS+Bz;bz6H z-c#W2pf4|}DWVnK>1n7Q(2uCRo&P8>VEqi%pEIf9ze4TrV==7g-k$VRsE4dM>3KLv zq9f)DqvM40g}S@Zdz!51yvLjTRY#?gn6qO2I9AC(iB^?n894j)BQFNcYw!WC=CRP= z;Vt!a@7CRhDl9G*7F{2gGYb&O!=1~>JZivlE!NVWGO9ZqX$k7OjLBqW2a_L?98s_q zqUwE*)v0zq&<)Z0N^PtldCQifPUdL#Ec^Ia`-?AiSBjw!6ObxGtEg?a9wwn1~1(?zFIsRt5c&*vf@eqye=M&4VR4(K^pUZx@P1zg`K9NAOzMn<>A}@plGx1Av9M0-0<&SPM_D2al&edaj+pBJ2wsk=nIj! zBtVn6$Fpg@0Zwx^dALgTFa23Fz3$~AU_&AcIABb;);B$ z`!Hy%5Tf{5BMC$WNUCBN&1e+oe|ut0E9Q|s3Th{#C`}&;!#$V=x2zg4&$8spquM=$ zrg#O@Klm5@r`?y^Oxo|D{c73!*0@QI6;HZ~n0A#&vWd7|MYUFwk|S^O3Q>hC)+P3~ z3KsW~4?jU8&NAi{*Qn+;{Q3C;8Awm7l}nZ;D+M`Ba)GlF)w((&D4i+NQ4AI@o z>^#m-q)(t6LrJ+*u2LFz9o>WRg8f;fBVa(nchp`fDwRSpl%h$qcanCAQLtq&-Xsv= z`^-MuF|@UHu+9)DDlo$vM|N*@C}BLpx<@ftr+ENq{<$IqSDNSi0plF6ZDuMM>lCbhh zu(@TiI{L>gi#uviygoT9>(YO-@qGiO2g9zY*-8_X@UzxA-M^mxvyZ^(t;<>(IMU*d zoVeITTWh#({{M%&*9jJVx4ZukD9AQBJY6dlSj2UTk%hPW_B@Hm9z((#hDabt(tRKQ zq~0(d(boYj92legeng`zgdB&I9$NFo5WPYu_NoMRk}?PC2Nf&%8k`_*Ri0hC2}Uh< zmRr&M4s85}#(gB98O0xs(5~;lcb@;2(BH|=vaV7~$MN~^A|Vn>_Vc!2#upALcMr|X zUKU&!T~2#l{aA`@)MK4NblMV{~JW5vf~ zK#n7BUt;wIs+)~B*^i7iun)g~84xX4yI8vl0LdC?{;Flsj}&vkHC1MK#Osrc(MyO< zvlOc!ZR{2R=IBiDC)oB7aQ)lfE9N3-bvnpGJD zB=@H zS&$3=8a=#QS#+4F$%-)g%$!CfmsIy!@3l=dP0+t1%vIm4T#Nlfdhxa2OSSo!Z$AKn zjka1#_l)3(Vu6J)1on%^kf{A`kN?}a6PUvo^rS+Zm&a-AX+Lv>tlTE93iH@)M^5s& zwzi&@`A2qZilHUj-Ve_b@H!dK%O^#n$>)r!8S<2>8Bqzk7+#mETB&k!s`bwXlRP|3 zbNLBqs;46UEojzQm_1{+xnh_!W@Rdo4(Z!6$YFe_X=M3N&GGKb!lC085`y?7TO0eG>UwekL)JKV*s!^@+YTrtDdY#opGDlTV&7q?9fx!-Lm$Z z8f_FC!AuhWLVvXTPGwm zHWdpep8|~bjB_32b@*0@<_yCPee;C)=Ka?7?*PX=#l(8FyPinP#BC)%k2H=>w8;6d zjuKLqqP+^Gh-j1l%_d`~DmGbi#1-2;~N+S+CR8gEo zHy*Z0zj%EJNjQh<+rXG#dX;ItHn$nCeFZ&XXpzF?rVRZhBV3>F(sz2XYKZ zxw2<`NI@BF*44dM6Vo~}7pcon&OGtpXdc8hcb17Pw%&v-E9rDRE)>LF?6%8R?G;oj zz*$3Rm5GH6sKpG07*=F#=^7Vu4nY!4g}=02`){gM8RA{KBW$9#Tx(=FoopG~r~ZOU znE%CdT>NZhaWXAfzspVS=>^a`S@-8`S~ zppk<$y`HO}jWCjur4|_7<0x|=EY=o|tv2OvsGGrb0|)0{x-#g0@h|uDm9xlDYjgai zfY+`IThLGoNTJTu3+PPnd0-Jirt=NYbJpPTp5V3EU)GYXUD=sIyOP4c%|$ z!An00{7(paGaB|2u0PLtABsI5CU2zN^{U9oF6M1 zVwLGAJ!tFDD_K$2LaO8?^TZT29e5#oVl?*IZAa7-|CN50^{`6lW|yO1Sx^ znRwY9T~MR-=%a|Bm$ssJ>#ejk`uR#B(OoR6wERWzcO6lAt9ZXc$b9Ba4P#E)mTZMt z6$8sDhb+^JE}U#&;~SEsV^;`B1!7&ge~G7Yx*G1&RVED&J5VGLsa_J!+nj>6M2@q2 z(z5m$BBNxm(@}O)B->)s2~12e(JP;A6I`+0lzQ!wQ1#ryN*?GLSKDrBhEnUPWp~9- z{Pp=9$Tbp{L~Mt`UbActF5zx7^63Sc%%fVsnAD^4M*P=yIVw=Bk8f!UQ^Y`9HDuPb zHA`J!|Gl8S+$>HMA8vgbCUa5yQWo{vAOwEummft&{03V@)d~@>I^C(j&0UD72Rzr- z4p%oh%|M|QKQl)lAr$@Sh}?V0yJ@$#c`-V4#V5F#9yUTkBf6l4zh_gipgC}3Ei7U! z)b8dDe@$G{zrS@-FEdtA|3iQ`$Tq8WuNEJc$iqjn3L*ijfVDkC^Ke>#RCG701QfY9 zswu!zW?n}KLevCy+fASY#ZmLOPg8n~vpMKj3t&{6*e&scn+C(k#;ty0g(_W z5{<`x6@(NyoY*Qtf?e{|=GZc~AIHCOU`5LCgWRMqcCc2}bpA7^vHTaY1gz4CAu4nlo_%-gw=$P54sm^nyuXLU@M-$mmbVZ*i%gdF&uu*JBAY>`#P2s?=jaaido=*h{+xgQz*MW zqv_x@Y1b`^j`0aDsic|?&ck3%5n?MzmQTCb?p(51r{x&=xdj<8P5m`R4)yl=@IW(d zv!I0S{Ntv87sYyEmKoNCOzOH15Po2VA&O}&6uM7A$SFN7(`I)MDfdqGOU1B%plGy) zD8mEV<6-m68{_)@U(yp_@YVrxLmITr!HOJuN;pck6;H6`WLRLvcZ!#EOnlkqp9eF= z0XG(qW>W0wmCW=!0=%GwDY)`Fd+GFi4uG90t|9v1sGsU!nY#B(f<*m@5hG7;iQ`fW zf<64fc_SNz_!{~a{u;yzpn)99A)fa?4reAQ6dggRCO&sK0D~H#4mP7fov;Esa8&zG zh(8t6hR_rvn#k@6%zxO(wXaqZ=e}mAW1T{AhI2Zr7EyHFM~|8heQAhqL!R4!t#SDJ zXd<{9iA4=JGsM#F;Ut>GO}nnz6VJ52=_rF*Q@1(TBM60M)I?+g?Q6swAWIvQm8$8! z?|6K{2sKo3Ih4K6>)5r@t>7Nmd=jIBCa=1&7;So%Sqh*d*QZVd6uah()C@k}!ng=uq8K8D?MA%J#yg3;ThNiEAt?zD_`k%9NsVHYQ=ZXj8^K!V!OSdk7% zprB}vKjM;kXE`b_ z;UZT>2!W#0!->XxsM|yoFDn!>tKkt} z{;m3q*2g3d|F}Z9<>xT4&pv*EoDdD#!_i{pp>t6=h^l!YX_w%3mH-0ci`w#*Pcv=L zK)jn=F~tyK+Ox2hFT`K>q{J zk-#n_==px8Y7b)Qe#q`8j#@lcSQ{WGT$U6E@T?^tdPG?Tj~S~>g3%|NO{{*6r?)9Z zWNkv$QZ4loXhO6na}b8}q9>O`l&k8Oz9_q=^0>2^%S8hvTmj>A%8dhiK+$xW~ zC>8G6X1YhSK-=VFz5LYDF5sA0!P<*hhGM%wIv*vz%!k9K2wn|iN(S)ot{#xu5bru$ z#T<1o;LtP&EbV}W*L-2YOdR>_v3@mF>&Q}?ZS#TgtM&_l z1DWrqals@_b%k87aMqO~Dy|`Mm*&hmg(tw?txG|}<8k$+E^`LHSYyxogoVO|%8<^3 zOpyqe*$qNm*g9IdBX|Q7#vHLw3&lW93IlW}L(4jq+*7%1|Hg}Oy*A83cXenY}$SlEe6puiU1S85-$z0KC$SO_AN1HNn zMpjtUsw2h9J$HjM)O4qoVY07OohX~v{|*NZLo9aUmLX25Lz-Lz{0dR!c#YFl8M^`i zT}h_CJ}_P|!oCj@-#S+!>TKo8a{1Pt@k`5aD4->)BDje{M* zq)Tl6b(?leuh0ncfwf4nb2LS>pahGKi7?A89W+^jk&=jjEnabOlJZ|N{{mrbUNAsW zB#o8DPF`EHgGW37l!QMDQ(c>v5p_g6NPCCacvq5Nwuwy~IQYS}B8b0mg?IkF%En|J z4p3au2LLm&$&a4e^c^G5-ZLV@KbY&UsrFf;Cs77aI=?aLm9zr;2NQYV3_Kt`nF26d zp7s^Evx#BA(obze1@;+3s=}H}$?0R4SpTUNDomCewa{Q*9;Ec1$Y(2=8nA71a2EW! zNYX+mhnE0_;rTHVf)jOlCo ze+7O7Y)DPpz%qHe;36HlfFbU&B#WD__Ipo|<7;KnbK`O+n8`;W0R@XbQCLZWwh<$@OkXlGc^PJ1L2 zt0U{CDu5wQkreq`>v@jQs__rE5&HRI_gbYxIKC&V*LJR&pDxuQnaDZ$3IGCRZ8qMc z?8Ov1IIg-{`{u*St6WYKPyZFRr$!_|Z#79k;>OOE5cse5_+JmhJW05cGk?~=0PQ!? z3&UdsF)9d|9TdVH;JW`qCIxrIJbQEAq%zkUK}NSr@_KCnD`{ak45Q@g1U{j?N<=5z5>Iw-KXMjB(`r-VZM;bekVDZtCRNGl&92}oMKb$9zr-THoMqKNA z9*l{qf$bfaQwf8&DtzY+^S0#u3i?ceHOv8FTtj&gZ;Q4;H=3^&%TvFd1O9GH-YW#voFGmR0uw#>=5<699m+pQ5&IO-V z(y-OG(HOjzY^U0HbVy`nKa@5t?XU8IIz!8#A-pD3bx7f*(qgQnjF8#;;i2kmK4fEZ z!n_L}9oB30r?gj;=VQZ_Y(2`-4W8v!4v;myErE=Pp7vL?S{~l6q4w}V%Z0C@7J0TW zof;W1y;X4kd}g4X1~O&3U?e)gT_fju>t}0C1E4@(@&$%ZXO&Y7&pFsOHkd5}Ee>t- z0G*7hAs|HCTRg@}piV3wH~L~pBPsjkQ-M4_Dgm_KPUu{I6&#nZ zIgjG0$m^2$2AQ&Ce414V><@STh-+z3IyM4{H@yiqPeq>+UX!44fNpcwc0~^yBM`T*lqlud#sUoM*zU)ZxF8Zzq=fIAy8a*-i4#h4+ zp8^y?ds{s)WEEv>?eVW@Jms`{m&8qk!`H<+EUQYT=#Md}dq7Dh~+LO2+3#z~4) z0@)nR#&4Z{Q)jDwuaR#1ZXhnHN29;B0(CvKqLOkL*J6u{2Xx&O5)6n(A>9YmD@6Ar z2-i+A)K>J0T-ejZS59yfY$C?=!cdVSO@IR?0vysdi~LyZYO{0m2nI?%qD-Rw0tO9sgpsaa-Fe?0p?(WjK~YPUEzj# zxtfTu?O5x_0Q@rn{PM%U@xdNqX!HNxk z>7$OII=@D0!Gd<5Kf^F)Bw!ASAew;$LL|G`iilmzQa=6GF?vj_b;f1GWEGsH=9+oq z&}UjGd-`GWEZlKo?Ph#ggTBtGW?pe$oAN+x7Xdy0sh4CcPyqK^zu<6zNY$?Q98( zf^VZS#k)!rtZOBfVX_6J$Y3%Qx1$dZA zD&Y3CPGC0^1XWQ8tfF0w`BYY@C{1&8`+7C8+^{FGbk3w1n>U=kiEGJJm*~29$fvJ& z=ImK+Lhc-N&X8FV)jId>B z<;`mf5i;wU1H{2#hI2}&y`O|AG?;a~kF4QhK3?0RTq%W3NpdheKNa#9M&9x+Y47Cl z-8a9-6)}zlj_XEtY94(pQ-oZV223l^J}xSSs_gzUI+f^ut((&U2~k*>wE-=4G*V6} zkz70Un)Rx=ZuwZNoQI=Wl(v;nWLtFACt)ua3V%>I3bc(8PcLl?9wqPs;S{I~eUGxW zuX=7XsYHZa+D@wPH8yCI3UJl?PtSEjX)FbDc)Fr#l@sGuy9Z&gs_Kok~X6sxb-L%LdpET}`x(LZV zLVLUt-oBUJcKbYRZL%^5>L-A&WqooJ`&~>#MkULd*==6(TV1JItV#S%t;-wL*~23b=^Zuq>P3D#JZjPabP_Hy|?d<}a~q^u>* zL}=xtzF;{aTqd*4U_fzgu6OvXwq z=zG%fKK|ax)g4qdG7%sx) ziNFi~^4-E`p;Dv#p8>V9|KE%M%Exu}ZV~&BeC!xb?y=>pweX|D+EMdZZ$2TEo`l(B6b47}!J~A?$JBavQv&$^(E()&*#xc^09#AO98xO@ zuvUMb{P;{hxdF9hDp&1cJ4dcd9)^XPR$MC`e_1E3iV@NiQhsrXRvY@hW2Q8Ep z=lPaY2wnu7xATojUtmFRaV;_T-zhiO8t0nZ!yO-Goc{}3q3iI_n>8SU)yeV^$OdTr z){OD4Ji*b`v|~3FSLqnLAbc<-7vOa|qLwB~t6<}+5+=(|=-NBvjV$cC}^*67^o+I(YR^oYxJFR9fL%`4F7;@d&rcBec#a^Ppe76ln zSq1+J!j^fyw*?g>mI%QX$+92fkQ6L%Ua^IFKR75C{C2%b;|C2$h^tz{g&*7_?@8N&i>5x#pHV-ITg5J033^i9~^~!Eiwe zNLn=8TW!)jz`sGFb0RcQd`s%to?mKG*%_V0qpZ5!5=H$%s5}sakCxHZ+MbnY>?cZtx*d7w z1;&UVRvQXnWE*)O)HG?kEusM(cgPSNGIZWloq>}60&wB|P0qZv5?6iF^OsVpWm4cPFc9#-BXPAB*yhYJ;y5%wI8;B?mTj@uW028^p={JzPb0N;Mvh%3TGD?Bjbt#KnK*%*F`Fb;D(?QMjm~DJt>Z>Cl7ZYmOwL=V)`p9(3|-{L<*8 zD|d!ZJNmTYmY`Ccc<68ju~_W^pE=+)umjKG?1g^^Rd8yM-9+_NeQBSN8gDpY7ypwx z2}T1)K*B~&6oPdv-?r~CRB%3u>TUvdf{oF;h$xlWLWuSKEa1E2!fRhL$j|Nar*D%J z;i{UiP{ zbaZAS;t6oN-C~3+4(6P4Jd(U1Vi(Azss`xl~fVQ#omya{o6yq5-N5{AvK9oZ% zryJc9aF>btR^eb5;#jw7eniXh3dC;Bp@jWXd_TKOpFa#zUmw3dfV+0WB6kLM*Vr$G zAn(qWlM(d&&@t6F03EgU+Y(v@xSlrj<;!;!q^1<>oIsm206i2K;x1dWHmAm5ea$#I z>uq>)*L9_H3dO^O5@lAJkqeno66>#{5pQ{AEyrbmfuMsD|4%|@aOBU)VGs%o^}#`w zagA>?e%q+^i@;(nwvQhKE~F=Oo?n(982S1FHO)9!558#zgCit&L%?_1Ge^V&go)$I zYwh*elH1{HW{#`fN~&&OWoo{(V~DVO^`Al@o2KgNEYm2~hz3v+B)EJgL4oZuQ+q>h zY-jmjV9YEdG%+^x6GS=pn46<|q8;I~SGLkvVJ@pgvSU9@YbVIx6M^_OrQ4lrE(4XBiL^&A; z4?u|&%A7c}_Im6w?a3c6`a_$vd9El<=V_vq( zZeq2}AbX4^q>ZY+NR|8^U@2y|J3C=nAFA4|Gf^hHaea7;G;INK#Qs}I`EwSrARF7) zuR(A97M-N-isP=9^mq(T0{wHt2GqOH#_M7e;~lFK#wF07WB4F#y{1yx6*CxNd}nZV z%1_vCJ6v_^e!mvVVt+>4Vh+@B^<@o!heeUF1maEGxPsqVEXaZN1atQ|XqK6zX~;-o z!Q{G?6N!U*m`82rdyDVarOyT45`6sl$NL0+{#qM_JCi{BFD;my&fjzbLqtb#Q@Dzjk=fa4NR3* z=~xk;g79QDGg2wr#}j^|pu7QBeP0-pQ>?~ic)?tdGKEQYtm5K`@JH^@2eou1&<_ewvfs9-yY~2{OW^t~Ll91D zBYP8D%gpw-yJusBDakAj8=A3ouCOse3$;J->TX^Cd6ngEI7bJ(-mVGV5;| zroprV(jeSIQw?Iz#SWSD`GCNoLI{y(Qrn1Z9)L{6FRaUyP>{G=i%4gp^rd*uj$(n(b$C%B2T{PEmU*8e`RZ5)%pdIADIa$zSYM*TLKFMRxU zGP1Y6(nzB{VIO9Ebaz(aZf$OYO<(W4VD!ELfdmx6lcx6)*yhrdvhqfIg8oepmvrQBo z!DlG#vF2&7py(Y$k{}vUS*0QPzl}y^XN-hj0pn)W;&WRC?c(o4$(tIwUybof#%*{7 zP@K3cx06D=I9LT?isUwMK{*j>sXB8iYeF7mDWnm3n~Jg>41fw^RviG{But$9R8|1}w8uwEgMGJC+hm*X>H?=-Ew7?g> zmYe#bM)DM0k1S6tRErqZC>?uVz)H zElXv3%ei`|0qSftQOIELdQ=FBFx=|^EWP4mQ<2YX@qXyX(aq>KyGj&voYH2lTn1ZQ z{;b5ishL_mc%Vl0 zJ}82aOWEwoI$8*{e61_oQ4w1ncNm~0RsC8cx&C@vPhNm|ZMtT?P+n$eJH{OS=SAt) z*~cTyMp(6Lr{9WAdTMNsl)$)o8l4MZF`FkX#<+jMOj!m*__hKnABh|=fz=A$id&>( z+!Re5R-*e{_ef<@@OUAC(0R6BIvRGB6$lXW9G8utCoO;I?1`9EF5KkPCC;Cxy7Kpw z&BMJ(wFcE2)4yVCkZfS3hR+0ELPqEbTs2=?x8&5KBo{Fnim&Pu`k?_~YBR;Ij}GQ_ z5FvavQ2Ick@5=>G@!bPLtIDg3n5 zP}_ne@EnVt2hLp%7Dm}z&NKUlC7yl5i3s+$S{OTv0ZG2o#mZQ*yFj2W*UHMM_j!>k z{MJz*es=^I77AAKg95uf_PK2tK!G3mTYqiFK8t_ zOE)-zqFNpRi-bh0KfW+xoa(p`

    EupQN)l!;4x*&qdn2Wu74|@Crn}IernbQl7-#dq$rpFz)^eF}PpT-*u@wXl z$btw^DmNv+QfhqlF4IkkD7G-logpmtP6f*}c+119E!MCh2Z4Bn`zcte{fq}}4!`HC zr@=v5g>}uoJ)xw(D_T*brt%D3Hd%36_(E!qD8LE`{Wp-aCe zKo>%Lodr%l7`KB0o5X zV+y)4vA%O@rvU-7$FQiBCwc!jTeRazWX0hgNMccjxA}^+J{sLlVc$oM;}QP@i6!W9 z)O|nSMi0*W@sArTL!@!kgS4D}Kw;6*0iN=obO=q!DUjd#K#+=Wm<80am|O%_7f^pY zFcI;`v}+0>2D;0!9*zTm|D8?`hbVEh+~_)sprpG7|R!GhY=x4t(c(xr`&O;BV6gMRq@DW8dAkOlfSkhluGeP z+9EP+eo8G0LD8f1NBFqeIG?al{)-&h zU5_Z$m#s~}zha)#VG51bf3)cavZ!d8wb~w)B*8WTf)T2-Uae)en&Y zeJ@|)z&!?8!( z^;a@Ux_6L82IzOHaJIvf`Xzl$#a(;_KdZ+-Izi^;USyTp`&L({;5#M>DAc7rnD}{f zfYEwl*dHo>PQ#1bJ;-(m%y$}_&Mp?v88Dm|(#yOtofM{S4a(`3c{;4@jpZGN1zHg}&^uHBE*o z2`B;)$yW`RUxfD%HDNuiN6w%kyion!|#ka!1a zMB7o22g`N_*25Uw8iZp86ynoM8$pdkH3Gli5Trn}FjC>+qpH$@bI4 z=_36ZxyH~_E5I<5vDQ(?jListgj&Yd}O*x+*GD z-E-B>l&7xny--15B$NSOF7p|4_dvelE%b))70se6-1U5L9)S$ZlXKFm9q^$SXHWWm zyTa>Vzy+rUyT@Z;(^e!(-Iaso-xczDEjGN8;9c$lyQc)4rBFS|jr~+gY6}t>dk=Z- zf#o2{VK*>6UjqXE2R_q-G_t#ULDi^7JlCj?XrfK4x)N=>2 z{3HyLm4+$YS655E=;H>J5m+4zq?x$ndCVF5q z@hbu>fzwhI^|a2j(8me9^=cXLunmqzXES$Sj;L`F`mG4}Ch!X6m_VnQ7JonQ5V{1| z#Thcq`gx8mzsYj&09i@X6bgFg*@RA?4EtLh_g3Q%!s+DKUd=c&)gpeChPj)pl;E!D zFc+V!Q(g@9j}&i3y48PnFx@pW05hw6Uxu{!Yqi+D_{GL=WrzJoFo3XWHuEMjk$rSFL4&m=tAYT@61{7H-SLh>M__fzpqHYWY80WPzuC$k4U8Rz2?JT? zCX3r47#T}D!?svkP!=k^MSHz$J9ACjG>+|9D_!%V*zuZ+(%#PBxPlyiR#nagHw$>ufakAK&SHkFO zkTw&)ytUE9j{yU^j!LPL)4l=vqks^HAp&}L$4YudmPcL(yAeuk)X!4mf)xgkZ>idL zCO#g$UrH7n<67;Yb^LsSf17$&^E)c`hT5|3=g+h2dkd#T^*#l+?Np_ym=JL$Gn5@l z9sgj@g^7tD8Ww&}ZQO8i>%zLldROQ!XU9m6RO^wArl7hm-P$(EBuztcx+QJV}$A@gqa0DqEEVoJ{ zPJ69oQ2o(@k9!F}Fl?kv`$lT{XLZWfeF_5^VXDM`{O@jp-UH=SxUhMsxKRy`An$vgGSt_+V^-I}kHo9|BA5JZg0YX9`Q<5D+asLi>gZ2&uM$b?iLZUpwSor$iK@Ivyas zvWJT^?zjdDl!&m(pw&ivkow^>Svy8`5CI3WbG7Yakvi4eMacurM0I8s%-dHyvJO8i zf3!@kI8>*PXw$<#B};#%(G`IE1XN@bi*X;5WSI?We`?scq=+`+YXMs18!wcpMN~+Z zaT0Srvm6~WT=N4$eaAe#xKSIsGt zp@WG-7=pCx27_Hjx)2r|4=15WD_l^y_&PGN?C7sIotXAB7ehI%KQ_EY$m(E4g`k@E z;tCvsDbzFJrDqfe_h$9^K|m+%)CD*%2$w7VA<50G4Pe6|_{T+EsT;MwX&!cxtA6** z2N8i2#yba}q<-->ITKZ(5p$CfsR{896R}Y4)b5V z0ftj#dgM* zjE1wk7x(-K2HcpFTPGrgFJZ9pGvO;}GcKojS=b3-N0a5)5l&+bl`6#DFy3FVoJU^R z!R=1;OwKWjd8Sp$R#{axjq_eEV&VyAk{D2tCb8t?h_Y?HHA>@Ts4e6W&L6CIyMA#M zHA6K_35?+B3Hg#fW&qNBUfQX8?Quu^R=ywad3ht=l1!rLVJ5i0F79JC86=CI@DU!Y zMVR|=t4g$#_|i_erh2&X<1HgL(M@#V5h}$S`9y28TpsWENXH1gs2LGb(gMWRz$&fm z&iJ)0RyHU>;7Kf?GYaL`?BYNvRrN*JJC7Xpe_Lj4Gh^7{Tl+DmWkqLN_*>}B&^`^& zipjdFLr=6dkm4|4h$Q)*Ui21lEE#&+PIjklov>#@r)}|mfWR@s-Cm9{Z0P4R3Qu}0?^Ns1T+J|a$i=N{GMe9^lxWc# zUg{pV7+t7N1KL8eZ!9(;ajfVSb$Yqk3)DP8=0N~&xIbS2h1KkcY010wRiy_0i}`+T zrv`#%*WGH9d(@)^@Z(IJmbMl2Hv+e5GQw0yG>b7*mGylM9k1Z=IqriaQ@H898`o+k zDBC(wO;Ax|Q)0@Z`)~LU*Tk(bSf!_K%t~-fP$#I4L?lD;`D2g8#y$H_m-#a3ql>$Z z8^5C3DXF7CLe=XjPw-nQ%g>FU)SVD0`qY3>ARF^fok54og_blSaX!!N7#87)auWx& z=cXnmH{EQjK8yNK?eMvVo=)6+j107CZG{DWlY0%&pfPp8kQ=<^-OfpBGNEh0vU8b{ z$wdvW^O>3W=@Xs8J5;p2-XWcg)gNg$_L60YBHqBHP7&j9{&RZ7_1JYaZ6S}zr@C^& zU^H~eUAh=399sdrujcolsmkS(OJI?<)@Q%!!Difs?uiu!;qM*q-Pus8Z@wiM4Wr3P!`fypnT=#qw6dJbS=cw9YXYLB8dqs@W>dDF*DVqNBC2x>m9AdB55np=VR-0{^#Ty^$Xf`GTA`Xr> zqkr`8GS#c^xZx->8&>Bx?19@!#9=tzPFMxpw=pd18EQ#y8-9Zto+B7Scm9%kIbO*| z@D_CUtJ)u>yVOSgD9@Z5O1Zg&k|g_E&RT&+1&-&?-L2L1b|<)Tijw+0qBY_i$ehUQ zANLIDR<)(I5e>a!;RRacts>o1C9)TjW8{$oVVRvC&FZMxB}(_Mv4Zi_ZX~xD6V(7b zfdO)1UlK8)tL+(~rCg3sFVd14f(chPPW`a|1YT>O4)Ax1`0RPYi6i;p->V>CU;Xt6 zjjo5I3ZKj{H+%e=Dy_9aijXpic2I5i#T$!G=#V8Jpt-4d&S9Wzz(%)!Wdrah@9H!+ z;ZZ4tLo|qtK4m7{QSk2Sd`AbOCx@u>9XU29o$>5Kh+JW9X-MmD0RyZ)m8SK8UcO~w z=bQr;T=A38RsLVmS~t?D(gu1V5_~`0Ch5C<2f7qx$Zmh3#oX_?a4%sVw63I7rG~|k zp|_XU>PjM<(06NJ3dbcTK-QDEdWcAV8-@u$Yho|A;pnVk>mV{h;6Ap@xh?jHi)FQo z09)`$b9XCp#`&8K!oZ}DF@{0*2XkcD~2gvNtMtTTji>68bidQ>!rbWHGM4*w! z+!Qup%k&aS5OPQhbxrBK%*Rf<4%ToyD^5z%174`%QVu71Kdz+jhL+a^5t;CaqR#LdIJ4Rpy2<{Xp3zA& z&T7LPbiD?u7ELnIW+gxpU{6GerJT=Lm1&j7y%%9z|XDA(4UWL0)0$!GfhFUF%RxKNYw7m_^_4-LR zCAe>s8-cKu!WmHWI?fY~EvRel;shYagXJc)(O>z7VABSO+uhxIav=?r=6J%@KQqv& z5+1dZf3LZ*jhJ$4Ppd#*&qV}l2+8~m%v&Mes_MX5mHc_4bOT$Hpj#m5l`{p^ua9iO z#iA_SK zOZD+BjhDYd89~ZPWm)du5RVx+;CAKCDFL?g;CyRO&S?saKqii$a}GRvqg-mfzvow! zp@0DZ`xWaK!}a=CB#Sps(u#(r8*skQDH|(doyKk|nV`P7=cXPiS>gMYz1qHfv8J^9 zISyQ!6_PC$u}H;>Wg*LalHFCl@@4H|ufbop;nd+q8*^;Ou4aP;F%P|qKMg~HSHBG_ zBG+l0z^kM-h^12#wFi&Gr8}rL+5b{RYI&{ox9H;jpiax|v#3~1)~bj(vN`Z7rjVKD zY<<`{CQC(YQ000H&bw7<0{$1m@0{1KH)k2w2#aT_WQqW1U|TmJUB{p8*5(m%C;haU{H3EaFbGzv^E^SXjFhrM|*!&1BP+Z~7-{yQNHVVf$eo_v>rx zKZtc06n&EM={K|hA&K}?hf~pw#a6~S&XKZzU9;ET6;f=u*S|_^UF!ZbBd=5y32$tD zI&RJ!t^OcWY;!DJF0B$~;h~4{wf~phKZqGFFJ)k8cpoWoPUHZ+>TXCwu`J zJDKlwr|#1XqKLR531mA2TX>hTTeLlNRE&KTzCq6aw$W6n+iE&2PZRwXq-FL26$+g@ z4FIOkWiHAeG6kef8}?#T5dA`eiM^AxbXC!OOSkH@W*-+rOcSOYh z$`5bOD|*uphJt$zT9FNmT8?gnj)NsPxzY(^-4yn?Q}b3z;7wG0kKVNpQowrSe}s-J zejz0pgk4@YYUxlBnJDNvw@f*082gC~?#p`4aBH%zmY39MNgGi;iLB(GmkL4SyR38* zOd?<7BYcy}B-mALqz<|Z=g?DcTF-;OJdXf|Go@1RsVIN$iD!C45j4z~hD?Qcs+5k; za320`tQjFUC_kI22dTA!o`Cby%H;Dev}#VwO4AG&qQ0<-t(f=;3OU$l@yZ z{8hL)6664~)`@M-HMS*Wpw5^syf2NX427P6*P@>nMKk94(6p|7en0m-H9}9OBf5&E=RDtRhi}#P zlWn@Tcf0Y7_2n*$d5h{L!qBt4%3NN0(A#!};+m8*10&dL9!r_i`{Y)>_gL700yvaV z3~K_GAt|vAI5}ykN8!CFmN3HzI{^MR)%^N6#I#Jd^?;E_K(n94@QHD@DF|sg6|A4Y z3$}m;*jwrV#m^^jj`!Qpi@XxBP6*HIk=NB1F5?1eu^2fs=M+?;clY))6nkqO#Z=TOwJ-kn!_ckI z<{&n+!;4W9W)P%E=&l8O(TG-tSXqUd<>)P6l8~A)VCG^Q>jZpHbup6(FrMH6Orwe> z3={g*hk(1f0nZlE^>(n_8WK-huoAk#&^QsWz1;2ml5MSrg4N5i1ASOh6L9;5`%7YC zJsYoEOe!vtq*<&Wjf2A;@D%}=;SWX& z0D7Afg_MpW`L!a+72G8Bd!6AUEID*GCj=xqZ}q z7oCMGWXHMkn|LHh#<^apA`erOa2a){JmA-YPuCo*6cRHz1W^$BR2Y7pbT4^*UNVAW zi?$}Mklor-Ok&8_u$A&8A_D<@s>1&4-k=dgW+!C%iYe9%V?dgd3NgQIj zB5V&jec?rA*(p0#SIT=YJ77(0?s^vQd`9emyze%t?ZWl~!E1FbmPY3+9AM52DcOjQJEi6) zys_3nhlqQffRui_67-%xAqhUmy0@ZvTd~`G{l$6C`#aM)ECJU=YI7TXdWV@@%kThA zA&{G21B>II*6(Og649yQudU#>(?xM!=vGb=hB&LAokNh;*i3}7Kg6#Xl6|H{bkhnvdC4X8;rSs zZal0!of8_vJPG2@$m2@Hy?MnSS#tlQPFUQgGm3{BGUWyH_fM09<^&)SFzlEtUt#bR zN-^X__$m98!#?}S!Yf`b+8MV=zHGAZ{fOVsjUEYoP2~zQX&u?ZCJZ4I$0#uB(|b8( z!PXsvYBB9g-b0|2vW}5KTu3q;<*k0h2P$kX7PTC*p>EZom{T1mb6XJq%S|a$lz6~| zheN%`@s`WQ&kBE_=@*_g-#RCmT>c12%*?oRZ5CPB^|gv$IJ7CY{m8Z^et4ay&#+?R zFAdU}RL?N!4j;c^pn@m9_LcSB6@N)~qj3UMP>O8zK{v%Vozrj&H7g|58eR7((K#8S zOB}m^K?6e@v#JI?c~a|L#!eUfnil7+IZf1MT`G6Zwz(ZuO8;tH@&k^?S&8SYKqVOy z++P?b7{M{8Chs03{*#bzf`c?S4B#Sj(GHvX9QCfbgW%qWOOMb!U4lUBzAT+KwcDmx zkt;}5c}^CGI*zv{5Keb8EJ#BjgtyHi&U>poceT0hFO064B8lF5esva@Xqcu9 zu=ly@l9{J8zp-!^btfT<(Ai~5Fya*20Db!1g~0J4ehT#(llCB2)?4(c5T)3im9ZVc zv~oa&==Xva6=$X?;cB-R(>Pgj`?;j5o1g_^7uoa=fB5H0OTVb zr`GR=%)9=(X&ZTn>Cxz7hO0 z(*kq?Th9Acf^e7-L@XB0^^kJknf2T=?o`6rn8lf~6H>9DS4<0NfQrMQ7f00caf8)b|FKbHyij=Y6+RQZak5thlSaH6Kd1qeRfr=9 zM4OO9_b1-@glXzIf#W^rqG!M>M%`<(G&qAx#FwZQ;88Md?SsG{>!QZ@gOcf|-^L-f zz0SW%)2K29wT=D^Nb){o-WDElcB6>#J&rdB#^0jYHuJIXCnC0g#pvU%G`Jr%WXtsC z)BZASt)t z2jY$JSzV-0q3AK-L*KP|*F>g?FwRMtED3^RwUaoi5b0-(u2ZR7m)i15aZh@Kh;bT6 z3%;)b6~0MI86CbW;E)ZUo5bA}aQHv)C5IVNMlFw-NV|4oT1tt1|7tVlJCelv$NIj~ zZFnvQOqD?g9ykHS*?nG=f&1ogIu-oO3YI>ky{1a3>uX#cS+)u2MnJAbzkO1FgX*1& z9IxkNN7zt9BjYV%4zetx-3S<2GnsuuyIMWjeBt^}vI#urMdRR_d_}6hE?lh-Zd1#f zvzaiMUoox1bECBmY-XNcigtkYBJiN;b)kn~x)@Lr3MIR%7xLi~8?=AjizFcSgmlFZ z3Gou%Y5LtjHOo(R&H(&*`3GoYC=_BdxnKeM*wI}}P@sB?)Q(B$S+f`|N!(MoIWRtH zc3bia+A$5LX}VD+<5pn4ANmi(iefOTt!>^Ek@ffWRPSbUc)PAg7_a?B>^VoR*ji@M zO-gyh<)_YHA{47FVHS*xM~x;H;s&4hd?FD+v`g&cb3U1x-`g5`O9iq%^=BU>%P^Id zw%p?`FD!GMzw==j8~U+TePsYCJk`T&H_^;y6oy&69kFqz!ia?JhEvr^hCd5MT6DqH z)y)Ur06|oQDwuM3^0HFjo9Z#C#yWhnmjKtA?zLKu_or~5Ia{txJfu@=c9(&Ks`P81 z@1a=O%UnV;5bEi&KaK=9O|E)Zs3cHze0Z4gwfxIS(3xbOg@`i)Nbu=yk0|qA|Fik9 zB#jtgjO+oPIm9XQ;Zu0beuWc%1HimA^ig2asIHJUn#U))Qe*BIVVQfBGa8NVl=a!F zF7PPFUG9)AHx(dq&q9Sa+ z_iht)=8w& z=FV8)2olu3n?WpJ)BF_?u&jzDquEHd+X^z(wcl~Fhi-ESt=gtg68%dmWW?$hO>@78 zN>0;{rS?4L&W%W!#TNEH6^5f5YJ&0}w}k^+KVXo3#0g~-W_x9Ii}bD=D7CdL^3}1j zTbR8J3IrV@Z9$M%N-SzJ@8GQHaOj?!y%iG*7n-L$SKOTV?UxeCTB>0$F`ZpNTOe7` z*J}~|)q2}T@msjRueb{6lMb8wz2G^?n&vH_;N@|;%B0i>C$cTB{R)p2t+s8WCg{|D zIlZ=!Q-d)>2;~}jD9v|3n9<0t2JtBUrs-H_QTp-l>tiDiuUDZ` zRq3fD2BJekh*?Y-1fKjd6lmp*b zrlvU{2}|pr-sU6Os?GHDfh4Nflhv-}MNw^mD)+>XG1wnjZm3}bRiTg%E7r0No26Cj z*=YNV2mbVSEU@2tH#~4}=wA&LZy!-mcZjIL>HM2H>U^N16qm{Bqsf(_y5QN=kI4rH zF3YhovM;S+^7(qZAxQ@-B; zEXBI(Fy4gqS|mq)%YM77`a&-=I<2!Nz(y^&hZfSaxY<2<@f>-?&gqH2Dm-)6!Y59~ zSm`@&^sZlu_lXj#*&r3UOTE6{x>;0mq!UVKh9x)hrskYWBygjxjgL@5p*I~VNs578 zNoI1hKF~!nuk-FPFu$w3#-98WL=RnK6XC7R5v4%wtAAT%ga;O~ksCN%+LT;@PIr;w zZf-F@{fG{U4kW;L_%+=Lu6lflxKULy$X(<-171E5QqdtI6CFZUvcBQKI6DtxFpcni zb@BILZ`5?bcU`oFc#x0a9W6ySaeg*ub9bvK=-(oc>3!lO=jj?l<}@-*@6 zde3{E@uafbjOE%wtfc?-1)%7G)C>H#eMvq>*DwHkwmFpc)wNabx=2aSuAbAiXmh?4 zjH-dAc)qUkb2|h63|HHn+I9r;!A3f4gi%Zx~gQ~f8{lZWGi9U|eeHXGHOs7E! zC822_5K6Au!XIoW=?nDdH=?1CBq4W9NZh#q)s7U$vE+X#S+NwSlCJw>HhT?Bj$=-zu(5mN|Bf$W96^Fie!yn}~k8U?D3w80wQ z)RNLB7a-XV%`%V6(&{sf?4J^_&X_@%eGK&LN0vRbsE+*A?~}v1QQH@^rbGLYo#90j z$R+X`ZTqbhfB{jACXSojKD{H+{fA-dMXH4oDqvRgkI-SxE~yYhQ}-cItQdg7c5U1; zsOr}}mb0t%WNwD@HI(kbD#HMSbLap23EH_or1apajRCZ-b?UQSU|OzPufT75yLW7|iUm z3B$FgVV9XE`2|{tpkv5{?z=%&;Sac-LbhX(d#P+zA6{<{1l(y-jE{Fb zPcvFWHR|G;bsgU?IGqYaWi=H_er`iqAvG<|G_2;5KLCkg%{{D368)&z5M}4a&_;yrG1x9l_7R%(C;@x?r7&v%189#aqo#Wn*I9`~qJj-aVM_Sq8Nl2qG4c6_RE|KAe`s?vaK;Tp(iDlD&iFu5 z)h*c$X+B4w@hN#5B1FpvMn!Zdv7JkLB7Z=jbc zeYs5ysSjmD!KdiA`203;`sB`j{Fbas)*n_8Dw*o+!DOA=;!b~+X#91nsI>E8{}?9; zCKowgUk|-or!|MBzFYnv*7oQErUH66%3Vq$-m055Q^63jDo(KJ*1w)xq%pv~W*!0x zgO>F(7rBJrhLCUg@LKHQ?L#oWa1J%89Zib>b0R}e*!g^JnIB4DwK{9U z8b1wVDOcIiiZf9^chMiA^TXIi`Di*FvtEMZaNgI}a>u{S4aLc*z z!f$XB2da|8d?eZ|nefx*k*A`Mm1XbcP_f^t+6c>|WZog+B zXTWH>4lV;}Zlv%)@X22KUE|IYzUzx?PAq3G_-`GLP@O-?^78#mkhh?>P=7()=yjO8 z<5&==VYjGGF+ON_@C1zN`%;z1XFeC$dKnwK)VTFz>plaYhyZfO=ab7${eBl!J66?2 z0LQ3K=19ku@>tCAbqF`A>L#MdcF1JEX@jMqomdNJA}*hEmS{o_cg>cUOg;+C;=7?1K?$MrRx-G5E^;$iT!= zaspiTqW8!2!rY|a>Bg=DOSo5Qr>{L)W{DL_*CPwcHo6CH$-}6esJty-`nd{6d;^t} z>k@T;jrGP6G~Co0HUq^(9_cVhwe5zD6F=n--h?lFnqAVEyaY0fWyIQNvC6poNkuJ_b@M(eBjb4&6; z=V_0KW!u3Qbz@G9C%6v8=uvIEd$-Lhk56XMH6se*XWU%;{n zTaiX1`yali`|Yz|7NF}6LaQp0nqDst%!-kMeu>t947;x>-G*+otNQLm{qZ^1a7w!? zTOF=|^uoIlaBO6$lu;&fk&GpaO*SeI07K zxdaZ3s2fXMJ9zy`w`0_4SYajTF32K#igdkeFF`w}C(CAVA)?iTuTcO9PR=gLRCQOt z`t^4>~rsH4DwDS4SzX4O~P0s(w5vv5; zm&DI@Pq8wui+j`cqqF5twBGh@jL=2oPfF-=A{C+D5csPobMo$}vULqX>iS%4*)YX~ zUBkG4*b)gtsR@lsGATRqcxx{JnCpLkDopR~&oj}OSQkq-cTzJ&w-TIpd}#!em(|Vi zjT@Fs5qX>9IqoUq3=f^?516ii-w+pt5dZj$e%KM8vKmfb!xGPRdYT_bwnAvZ}(W zV|13I*#G!p&pzG6W|6p-8PQyHg$E9?f3}_6u@UX&o-i!8OD&I3CX$)1}oF z-8Tf4-U?Fv8%NI;J*0Jteel#cI4C8%=#jfleY+Z>M*ou;0|smWe&vx|?SZzMg-SK7 zN5L_-1q2>qz)G~6w?@Oz3=CKaKd1K9vHyB)g?5?64kcSM>i461_FCNu%8_{G+ zi8kchpbX@)PJgeW0!iT(!-^w0ds-}YiQom?-Ow()PMWdk5JVoaH)KB#E=~su$eeM>w>5J`ydN1XmOXe0yCl3gs0d-L9DF*XGWulKI@f84iEf7_X zu{L}C|Ks#UH!x%dPYZh1>i|aOw*qr-&KJjjI#@j*gj0V$T|CT5j>gf+`7QJGUl8U4^rO=zwDwGVaU zsfljEDE-2IM3D(3ew9zw6g$i}p>wOk@1HYz`)-x^^l9&l`!RxV?>_M&0_w}GRv77q zK0T=X0V@Ww_}^KYGyoF@R2Mz3=?B)b>qEO)P-bP-D4Z-KxzRejuUcRcU@+mR{hpoY zS#-@=rTgu7O!rna0u(52E>8A+g|(La3@ePJ(L$xQ=>?Ym2S$QV;6pQ5WtN6K91olu z8S;6OAHdYNwvk+s;N_AR+3Ft1eaTJ;Jli4mrSb=`L0dP2GU)i;5XN*IZ)k<@qMYuu zxnag4x~M8QX8i5XD3J;$F5m1bk1ipdSZZDVqsX$Sq^`@t=x9%5K79b0H%G&BU3-E* z>=DrKk$p{dxzQq>2Vyekzup^Sm13IKg$zViczlZ0iKZ&r{HXPXvgju0y7iuckzM6GT}CipDa47%@N+*kH5%vOyM40u-nq}pYN9R*)I0;Lyxpu z-K|%VRdL58$o4TTNYW~JebUW<-lgLoP+Oka#gM4N>NEa!|6Eq=C^k6D6}#TYX_AZ^ zbtgf+A&6OQr$d)&hmC}%R%ba3q8zd1)J1_>M_BQr%fUniu=@UbiQ6z)Z_r;)zR;GE z{hW^BPT^9vtRfGIo)FMoeeY#6*O2JDt9I%sE7jU(GBiAYNdm>{yQ!&9#lLL60o{po zZJ4l6fJ@a%#gqM=GPf+6jNRHI3?6!OHsT#g-x}CrYe1LAj(@yq0Q;7YRj^{5WuF`o z2Ev812;8w~!9Rq4U}N>?05bmu;ts}Qs0R&#A-bMqmS-G~0RpQRQwE6*eI|zIYF~c} zfW@Ry!8VxNpL)1VRsooUfO-+(a%7Z}7C^*3f>RnAjlCStTnaS0a&n*?XK+?<_ndG_ zvQASwXz=(Mz)T)WN5cahc${{0e9CbSkqRj8;2xx3lQH3GzcQe=yfOLn{ND@5^>-Ox z701Dt{9@2Q4^ZeDL8@n{mw8oJStx#TH1qMUu}JdI{g|G=aQ`Q74R{#_hcbs(I)VOp zl`28Kb22FWF&cX|j-0N1se*mHBUM}aW;}N+BHyp)rxLqxYY`=0fDjW4#b;eV{Y*R z&_T{RjA;R5;DeqQu#Fen8k-E;!kKLiB!w%dVGwkKW9V)UNdmpSB^X}zs;4{*dm5F) zrMCOeG8+#~3_S178hLz&@!W)VG^AFNwZ%t8vN`Imdu`?ZHq&pf$LN@V1WBC?Mj`bA zcYbm~XKSooKFLMb4cs`B_oEcM4ow20>ru}+J`U4+4t4^bSQHbH2PT!52nEaQGd>;< za&MD-k=Y!0Kr{OQt@w?ngOrMV2OzTXJH*^bHK#|yjg;(~3&-?+-REt%j}$GkC8(g+ zedp0~L(B{&1VKft=AVC0HYtUQUzgALw!TG>^TF1yj#_Y0~$WEwBgE5JUAbE6xK8JLS9tl&tz&G zFftgxbPn4Rf%^D+=NC`4AUR!~PeA)QqCY^txSwluFp#1r)6Nsd;h5*qzbU91gMp!^ zq`KU*&+i#HAB3RLu7pu4%;I#U#d_4djbc{jGapxi^KIcm)RmFTyf(Wp*uFz_*|9E| zT7&(RU^wcO<-4~vutbNx8NM?oa@)7ozf@ig0%zHH-K96UF)xt+iU29-Nk@NOjvs1k zDu@%}7xad|GRRd+_8*brZ?1cHkWsEsNgF>X>K3cnshpSQRt*EU0K#r4c@k}Wj$rvo z*|3jzz2ZH@uaw~Y7$OM!(nI5+V1fH3#G@+p8tcJzSQZ6cZs^PXeUA#bg~8tbaoL_W z%R3kY%619u1Rs;fdN4#DQ%C{oSFvYqOmZ(krTWBWlXH{H43viW#XE#9mcy9g4qa@( z#^-;vN&In|BKb7sS~HdhwPtnAoPW17>YS6V*o$|#4(X#7MV>dQx%03NaQ@wL)&Kso z7V&)_*_RaKzo%G#``pT}eYhybW!nc|JWpFhb;9qxfsl3QJ~{@q{sG8(K$Rh%tHtrP z`#x!D7)4|Uiu8OhCBTZ4sOml>XIlBSj0tg(|!`7hA3O@tCOs_XxK0Pvl@p#xmW5$szAOS#`S-1D8pfEqL*(uJ+%Mhof zV%((Wk{1$LmpB1nJ_+x6E=Wy107Pf%lTU9J(9-TAlpc&~Z-juUM~pvHoe$ z{>8Y>;`#qObf;;v09o!-d!&fqNY#ly3NPY2#@lXsXko`0+4~&6{GzRjN@RF8dC$6V zX6>viw^w;5E91gnKApVwAkF(L?KMG(_`64`UmTxr*mty3{nYz-JQ@ZiPyB+h*@>Ml zW%tW0?)*yXk~tnUmLy?-ZdTZar!K0?&n8UAe9j;oPErECetcBWwzQWHyv$J_#J1W% z(_pybOZaXO8Y@%9DQe8)+OfoQz4zG?=0ogdUMPF2#x?YyF>fiaSEZmdkg#W!S6g~N z9hBV4>bu^f1u!%uTXo35QZuNG#wdmPCqK(;VhN_C>Ph4_OxYfP{2uq?k~CmU#ILL- zr9#Vn?@LBukS1jaiM>y`O?x-+7m4;(R{n0g?kV|G3r$&sX8{E6VPCO4!i>7q98n<&Z2JW4kD3HCICgq9r+K+GLf_)j9hc^KJF304^%BJ#zpMr!x_`0 z=$~ao@i$%Y+Q{l-xTX%dd;3`zxga+^8pa$4{p$7nv@a|_rH-mBTQYD5c?F;wbQzYu&U(~*F&KNgVZUXN^f`$evuGzRyw_jmQXiswu;b=blYeg= zQia|jmB!21fZ`b?9z6CoVMxG%Ww*@RNYZVEge(*BR_d7CGZ%I{-iQ@R=!Qqz(klxb zLyrZDerF@N6>}>FpCnz5Ak(9dW|%#CpSx6WaC#yE5mBO#F`o?->S`m54QU{Yij>c& z%xi9ZkK1@RimMQ4u~<Y36WVhxR}WmBnm zKzLDi=^85JbL2T~uD&W>cQE6uJo4a^T}D;Q8FhmTb0BqGuyun;n)`Ni)8>em1o0Ip z!09@?8(PyVJ!-PsKm5NbPnhqwdu#2MM%&CbE3%}w)_ia&$^=7|ii`P9eLE8=XDbb~X7rQKc zxZA8vdNc8;_DV0WtudKR6^oxaKviYXi&b(WxzUF1co(B9DF|wBp^8kt^_6<=oPmZk zg0gz%U|lkFehISq`Z4BrG`4&Mp{YI6;yf>nl9rmh{yuowhz3^H_RmeUh%f%i{yc>5 z>>MuuM?kp0)~ZM%E`CH|Knxh~Px>?{!nc@Xi)bh=Ii_z98rNZSbRzvzNS+WY5Vo~{ zP-{9_ikukjgD*4_RoLx$Ng%6CN*!+tU}OznY+AgLId?heb4G6kMTytb7m?Ww>*!Uc z#+33cu#*!yUXt{yH%wQ7`4L=fPUq{e=+urI)CY*iz~9l@mBjL#IvDS1!<9IT$M&W zf1cv$J!6xPHKcuQUe=>Fm`C$*9~f20h;xOGl(lsFUPlT5{oWbcq<&Tg;buue5kHES&$e$5@%si?)G@0rp zfZjFKi9>c4e!HFgN2P}^QeX(-ew|et0gp6!xAlU0Z}k!XBjymWwdDA@nHipgA zqP^>MA;d|Z4Cf9*I2GUOO)i+tDs5DHIp%O^t4$d@-OBh z9Yu$71?h+%sk7{90Az;|Ym)etvSLjsRTLKRyl@i7m`4^k9=nHsMac%#g(<4~q&zoc ziW)FmupHQBdJ9J|*l@!-tD_fzb67r*{hKfZ-QJmON zV2+2Q8gmSSxGl60c1(?Bm8oKQoG@U=Nl>}*eciZoG}|_kPzm`JP+P5W7gKt-$I@t& zlcBhUnsNLX_{zQ*HYAcG(H3S{%28ak6@0%}(j6so@`gjSBE)7gq&6Pz{Xt>sv3L zaJHk$iH1TY;{-&B0F4zLq^f~K%|uOrmg0zKj=^M=&*Xn6oNM77sly^enhmxQ$pJ{G z-_->WD@-?UW@38N0OUpzI?cd}WGaQ{K@m1Tol9oOa&UKbX1JE013bz-i)fQzT!V8p zj8Q0rkorJZ?1DeGhls9)%c3ih;1shS#!5v-o!tv}X)e^2LX$CbY@_Ukf2qcJ1wC{c z^p*((G}Hh}^^T?iWeMw8pYPi1k-N#AjA8W930C^Ue#C9yGkZ+vYZ?PjF?uWYzEuPb z--?4TLSr?#?vN2%_n+cb=e=zz3VtVpM8d80W@L2Vdd2K^`0W?QvCL$k+9bT3%zwr)+|DBgJ8H z7O4_?Ju^32q6Iy?A9ELoac#*hdmWnPg9?7$o3>VyUBXd~fTJgb(on$h@jjg}(woLs zf5#&%uC=pow|wuFNdFIWZJGGW;sW-=FP|}V8)Y{vNthrxiKq=(@hgurnY^kE?U&6^ z+oVE~%+@RQ7uV#4>ZVZ|3ePvupE?FT7z(Q5Q^T$B){v;Kq1>c1MQt34s%( z;KTL-Ele=12$mu>R_*gA_=9Q>hWi`NS`+UbbTw0HxWF^=@E}vT;JScU{zHDwDN|=8 zUMMg&uc#DOd*#Zn5z1b>8&(!l!TTvB6C=WD*k zRx5=5|6gNon)p;`eTI_*v~ZDCs6fa;JQ4ePncQicbVw3jqgtvX+8IlI1Srj@YepyQ z9*Hc6=^}@#qhPXN*z;P%70>0etV`2&QRLB7Z zw4SNZrYv`fHWf-iE>Xk4k`XJsn?L0JVN)G9z;agb+kthdL5(R0RK08RKW!LL3C!(# zsCtgl^?<46awgD_aLJDUiP`x3RXSo8{$!y1ub#DOz*uF{rP}nIQ_NM>@*XoC(tNW{ zgtM5A_B&(aL#2AO_Ab@MtX5n;2K=WoGlA z7?v#08_`+cvo*IkUGNYmLISXCD;Qa>KcCfQClh}devHdTeZ|n?bZv8W{|)3_tlrz* zs&Vd`BC$$mgWQLqfczA0KC8HPC>Pz7fete$@Bf$4Id#!Snd@|~w1t&k(tu1ID9eO! zBO%Om;xi2uF`?G4mCT^g8rna75@_QuwyLz)Ui3^egh^tR5!UW?)Xw4!Q63ObMFmyT z#GJ1o5vmgTfVrWVRnU)oOA?y>r;r48OK!g7Kr;C7(85?_EI4$^ zSqYcAIkqSNxLDx$Pr;@e2s8&lYTOmCh{*?0-1t|$CQkcZFm`4s9KP(B=f*=eC7j#Z zw+C4ha3q?`wh(#C_0*H@ZNGp^z*?qQymnq_EM*h{9=|PCdC5`EjVg9woI`NUv<$MI z(m0j+r?>=ff}ai@8zm14WQQuGi16YS+jNgv)GN~{^Bc*LXqXrc;ml^w$l=8hXW0vGM(|H&X*!w7_8eKXw;~?m>>&` zJC$(b->_*39?|1ZE|*U>gnfO70>K6IhB0D7IZ5kfcyycSN5(XH-lMH-&A-nsIh}*3 zqFvD$R8DBcC?)WV8hs~pK=DGm#o+q6MHm_`A8qcgd$y% zwrHIHO>0tA+c(9DcRZmub&8Nz-wa=cC!{r(>Ml&yP;Hmea?#Tk$X`frzW*pZ4`gES zPlg#6VlKeDN+(GR1*F_cQhNzV>dQ}77eZV9c2?X$-OOq0*K#&bE9aw7B{G5_rOTI; zry&;?Nn%4|EF$=xKW?+4 z7F1Zm0?3~?W2v3`w@o{%ZF6H#6-0WSXHE4MKVB_1Ko9Ob7s1IZYA`ZLE$C`ui+21m zp~wu~dCCQkYHBNZr(^yi#Y~9NXd0>NEoMQ{RD^89(E!G-^<%Ea`ysiMQ=|=ObE}foY>oU~eQFg1qKTXILVFPJvtpVw* zMBR4k5HCbquz3q7+r=tarV7AxmW*tijn;7Z@AM6^I*pO_ApNya8o-NFiOF-x>+&A* zJp2_D_~`>azZv@VUE-&a)SV9|9}E^xh;w7(M|kE#YC59DeGrT&?(I-A|0;`jlsrACvO#AA-qIrY)Yq@YoE}Z5*?&V6bO= z`dru#=OTQp@2t)#2Bwzmm*_pY4C+6l?T{^dWQYk9 zxT^ckJp99-fkDvAr2~z&utn{w#kWMmdy&{Cyw5F5_=$atP)(`<9?tUPv!G&mG5Q2Y z*E6I!cofDUDB%Efu0iC`XM z(bu;F(92U!|Eutn{uBT0CV}9a!^Jf4L2%%*lSF*P8hv|S1$OTQo1%qH%RBN=vCSb} zTvzV8kE1u&UAYr0hlb-<3e+uy@*S;w$e4?P#LZmuT8$jVJ(EJt+har*T6evJSYFX) z-zRz>P#8IAI@VT{1x>Q%CwB?{`fsaAg~oBE&~%j#?qCVcf)9!FpGAR=p?7ncH! zIhz*);PTFazAaoaW;tE%dJ#1@x1V7{U9^t^I!Yi?ybyGO~(L7Nd;zGJKq9M#CIzm(|R00V>$qG>w z#9SObho-%=(T%DVwh4a6({Nef!lL}`+iU?@>h}U(Mh~aBIS~*PX603tC12_MS2HK3 zq&4m+E+(bUgI|oLvtTo@lyhw@HynTK^|1r-(UKjN=>krBMow-Sj2uMBlFeFyKpQI~tUe)PR! zD>NZ)Qx@iR+D|b*uKOc>jXGc3GC^9C|3fg1>=D3gWfo4n*Iq0L)G^lc4GTAN`v{ZB zHg>ntKFU8XX$`P?ebY!)AeO9oHOFF92a6m${O~pF z{#ir;t7PLRw9cJK+K=mYCKbILO*VCo(MA!L%Nn-kTsb+*qsV$!%=d?^!^rp^)U8+S zg`_}bnx&IqRxT?0vU(Mr@U_B#Q1R3?x3$*A=P3p+(ba?UW{9C6NjM~vF_#oGJdFXF z@@iAQITYzU$zitv61R|uh%j`gxuA&}tH(nFryGJV9|W~aljmSk$A(Y>!lmkhSD*gWqEBg3St$(`qjZ7Cbz=J8~b*sp-J zkxlbEG!DkDPc zC^w0525x`ImHa||?39wqQz#kLSE(i9#GOtMvC~*jcsmEaCAHu!)MGBWim#JvvLP!A!qq)ZlVN(bYf9$74PP6%eM^M*frnqdSHp0qe* z8ItDAq@m3GKp^*}u|>U{-QsoyCsTB^C)R#$_Wjt4UWhYs$(O4NCI>IA!DU{) z0nr7YyV~|;oxX0G7j0xb42J-@qdzQ2y}xov@)MH_jSfx8gDhp9;h5yt^k{7icKJwMB%P$y4>n+S2*m$ z^!6gDciF<&(X*SunVP@9f!Hvq`~o0a9~zObykT&*ql?Q?PD2dT1^x2+4=%Q}W5f;k z)zURFypRX>yPQu|fQ55x zMF#)KG&0^?g~G0gCUBgVrvjMSyhP2k7ts%bnX{&1oVjz@y7z1}~b{K%(ucGcq4*<)ucfsjO7un?llzgl|IV?(m7QheR?%2J_=y zV`CmqU+rog_>^eW42Lqr$=z9fo!>QG0En&O3CU^zuap9(WgP6j64^ z41tnw4kRBI8Lu_}yzAF^@4$mRoc^;EN&l4j?jo1;QgTo3w6>a8bTa|Bi^x$AoRksk zj~V}_x6B!(;;vyuw(rie5eii?)~54OmmOKMNF1ic$h0CHK;NDij_#5w`!{6O&JNxR zZpVq`ZMUT5D(bvGpx!p~KEc`PT`Uxln$h|B8-FvxR{zT*?)n>N zps8;{mqGEZe}KOtM#vvT=NTD2f^h~(s>?)H2Cu#Pj%4T2U~R80avI2Mk0)K2*X&KJ98jR)4-Okoa4+=@4%vc@m+ z*cjO|{x^ZFo$uB~POv**0j)JzoVR0ka2dvNVel^an?p4Ot~Ur?t!wzT|Nm-@n(33l zMDi?z43J8Xp)d;P23UzIY+pVOwyTY+w2c5qXRH`P=EJ`hoDq2Ki?^ysIUfa2NGd5N zKrXo)OT3Ji&t#LoPED*Lt-4rknz^aVe}rRWG{=Zqfv>+Uw(t2R`p4O=>FRE7=5I`d zbNM5-no0{?QnfDr0cL)9#sj?*LdSp*hd4F~>rK^9+nI^s#xX*Nwz0xsq5`q_yVsd# zcfG-v$gBk*JDeg+i`9IKJ>qJAUX<|5jfp2Rj@OHayY1D^!vG&4gogue@U= zsQYy14?W6*&UDM$&VS(12FNz!wx24F6QO>kPdZJF7Fd&nC1a3Xdlfn4%Tt8p5Ek}I z=1k4kZSF@k@q74wi&y_%YIe**ep>QLhuZXKe+&s$YzJ_l_g87s8z@Ea9yFZ#_lh|MbNe7oxFvUxE$Ln6Si29BPFV{Ow zOQ+{rm@v(`1w~z55O9ATjpk-rWCvcFd#h?Jbgjbb2C|Q`wH%1**V?V5Xi@%?EZh*Q zkp*rEYCG1;1{koi=KH@Z*+f4~#QcAP7`kOf0bA|VgSDZWVf=S1B6}i$Gw#7+TxhX{ z4(9!C6a0WF>$H*&nt+*xUXT1?F+DU0^}eTslYD#?^|CQf=M)3$Kb!nZv0-`%k#h3m zm1I(M@vQa%EcMhMz+cxRyblm1Q;v96C)F(x)0TpFqeli1$UvEo04*<5ZCTUI>(M@J zL|T4ZmJu3%SK9QmXK+3+h$cJLuC>=U!=|W@1{Z{Z5Q<2|+k@71-|{|iI2&IpiuoE> zY{OO~)kiK4vlLaTv59ONQtkj~lDQy|6BIJ7;I`%WWERQA?kU{b=d_B%VyFM8%M z)OP*n?79#yCd)x1;$VGK;Jxw77MS>K7YdjRNsWg4XX!nvjWNz}Uf3a${dxU<#L6xd-S7&^O^Kq|e?p z3cHd|F*$KG&{vnBr)K`Y0mxA{?VH*)Zxlk6VTM=w#VCOcv~vmsn7|t=Gj~>BVa@X2 z`%gtFT53SvD*vx>LR{VRrfEdB$1&@Eb5{}UHcpA|AUU2BB%|q+_$oFH8TfgUwQ$du zraWRpJOb1J+0Nlj&G+d_8@r?33{beZ%uQHUbX=NbzQcEQB`mR_2E`8oX zD*8kdC02ktjSN=PVx^_kR32`|dof7?Y)P2jTf?OBCDqeYLDdYeWj%HAJ2bc3WCP)t za=3WR{J3&n;EV>DLjLoB?;qZa@oxGMmAkqXXLJKPw~owdk5Ue)35%~dhki3VKfJy2 zK#*4SF0}M_mY5t!b_~tTeqZ?7Mg8sG)bnrMHdn-6dF%)NI#9CsY<2Wq#Ru_xs9w(dIDZXW>;RGezF;vNg(Q9; zr<4_Wm~UJ+F%Se7brXsAadCtbX8O1jniWBR16NpQRD5@QygF_O8Q3aMvnSZOo6pv{ z7&R>R)=ELSTbx96z#az%BZMD%94ZBI>aC`}W7;z5Rx8||#0^n%6I3j}^MpIu)WpFX zr?n(rZ5SOBrV$@WXdH`Y(C9WQvm8Xt8RPagS6@Uc=#OY#b z!pI|hj!NJCVO%DUCN=y$PVu{};;yj3XydnY?XB3v#L%=5wl?#$-W>|D+qCo1Vt&Lk zf1Fz}uVqS$-VDsko!qgt%ZN;xD5$(54fs{=!PP8M{{a(9UAwL;btdn43Est;M>?D` z?r50*h*khC;II;9gGHvqV)%}L zgBcrQaNi2h#=Vg^r>*e?b+xZS{1YHZz9r2|E@)qzyz8>r>s;mn*XTNT7L#2oU-(nMYDj)44y3hsXY3lbMM`AdUmef zoDLM5uA~-dOzI)|$0QD1$d^`K%!c)Yge8%^mND6|AgYPD61%L4rCkYyGEZz7e<$JD zCwOXR>2hR{z?+uiR6G1>eA_BFcW^{2*_HO_Bv1_rUp^z-EF_43)UG6@x$fX*{uuUVLZ^iQn`{A4&Xi_UkU_vqe3$i{-%nz!c-*6bqQDX~! zwkzOfAX|k?cg3zL7z<@uqxdiE78|X1k20j_zT9WyXbS zXZbf?gw${{Qa?KVS1`;jgoPnB6Kfs@5yFxuR%y+0Qwc&qN8iJc${Mnss)pj(4Y~2} zYmX|Aw7~9sg$KSPFVyF%^DzY&qs3n)*o^!&bh>Vu=h~KLkdc7pR%O^tAcvpgdKK`) zZH;S2BV<%UnX+Eh@3v9b+_I9~5B3M_)wYvM#IaopF=}B&3fBOy$2F`x(KK^8ozlG& z*uLfaZVN%R-W`WPGIEC|$6ynoZKWt~Sihao3LxaYMKB8j`v4of3BuREcoVR+Il}4}c@LBCunQKS+tRdb z5PcnZUeaVT*04;1WT!J`T?a-mc?8JG2mc?U67mReI~EP-F8&(Bt2Mqwh}B<*nhc^u z!n$<&l$^Po3FgL}|5OqpX0-$19Xbv|E%<4)-M!Tpu}@=l4kFcjk*wuZnxK%(#0L8Y z(u=&wN(_T1i7Eqow54d;Egws*b-=y*`G|AYEt7wc)Vme-4S>ibD*Qi11C#vd#*?H~ z{eiS*pNgxP>ZvBWXd)Tox6u>2k)&X5FjS`I)-GLg&I6n_m#p4NgCQG(p|;N<}5>eu|F^~sQ_;|J-rd4^L;_;u%&$Bk92Cg`J zyh763OOen-%@J%NwS~pDQ<{uI$2XgUKkBU+Ck@ME26|7g8;dS1E{?(f;jr?ZGXL6p zgvWojc_teI3&4pJ8YKy$V~B@Xd2$IzdV0G^DDj!w2O-n*sFy$;&lZjAYYGDs0}}Vo zsW?GhBYpdfVBM96$yT-B`EqVkrBSgGJ1U2$%h?cvVSK`_DSJ&_k&lW!NduU|gV2wN zHsneYiZiPnWeLb)50M`R&iWMjW*?u@uq?VjWKZkyzOb;K99xgw;pgme*Jyeti2^G*T@!uJ7b6a5K$oF*#aJprK0Ma58@!Icw9%c1y?+*zpKCx)^?F(`w(P zQ+N#~-5!jCT-GNJ_PU^P%wBubLgp-oB#ZO+Lp>`9Eww-|zan~BQR)G-o1>^M)osuP zVn9ex?8%FW@CA(BoE*aGF~5vde~?gY3rR@l{;Gw8&p(TEB>{XK3gneDxm(K471$C? zjxwbK=D2>vBof!|4SpzBZXmU#%V{uWC%WsLpDa?q$bIc9%P3XOW-jw479jeXt5rgS z&Y|8Fe;$@u#X<}G<@{SJimWd%2`bQOlM5(>_Ia!2D{_Pal(iBT_o2&1%nf|RzEK8u zQ}}p*Ev-{7u9+u+5YMMgE=%`1SHLY*vtgR0)50D=ODRo`$|vHSh6@E2G?Ce?z_Qt!$?Yk{HSTQe(ntQb&w{ZnCk5O%y6dTMg#T^{m2 zuG$rC-7C%#4C_|GQVu;;g41<`k#t4pWTdGZ|KV&7RfjoyG zTCMC@6!}Ao(af10bNI&c?9%@G|xyvhbJT9hz8uf z2UI!his}XHcttSzNc-_m{VxG!I^|yPswksf*+xRcfYl6g7bGGl~75t*N2@l8F-3 z>|cl*=Ud&zOG6Kt#v_JjEla$`DR?a2ta{1+J;8O5|JM!2Pb;AVk?Qmamvc@sLB=)uok# z`exU%dQ)@_gE4d`#nR!f;KXha+a~v`Am9_#zz^ZGy#-}by~KW^EPG%t`@uW2$FCv$ z4y>H6VLwTZQr8RG@(7S*+pQ`3g?E-a{u(}y!I<&Pv)!rE$z8)c;8E5$Sn_;?pk8*A}u%K}cb zRa4ITM!gi&aZo=$y&l2B#1doXJkHwzS+`TJ)m^L0 z2Q5EZ2v>RO@zy_-ct!>{cf-HZ^s~CtsvO@=0GDa+7|zbA%8dcK>T8L?+dCYA-6yQ? z{z?yx?XXF|J6PdI`srb=uoDar(bgt6VWN|Ope}Y@PuJd}e}#zk>;RI-Q2}OoTa|jS z$zx#`I43*ul8pnPmtqpEf6bsmE?~0cX@uk*JWDB8#IX9M`-F#WU`$X6r;tCXt4Vq# zpTOHUmc&Q8Rwy}76319WE9TQWjd9rY7CA|5mHtsBf~1=RQwsd(`7Hm*NAHi$$8`k3 z15gY#vRGkSE49zZ#ADgjMObo^X=Jz0)S{;WzojgRsA(qAIz_&^)3v1ao8 zDlz@Olw^PAY@%1Rx8PV%#Z^|=a$o3_C=BSY<4Z(*YX~}7q(UWnsRwodkUJbLU+_A< zx4V%KBzcWiz)Nw1jP+uJ^5EKFMe)FVi~i!x*aRE!I9zeyfwe6k$DeT`4#W2(qm7#1 z+ovd1uCRvto8b&fhdtzuyMrGRJAh3F{&0g=b3J9F*z&pLaQEwkdqSL=qz3l>zhV&M zs&Z9|w)%fE)m7AsRwb3G!nGO#4#wb{w@rW`IDe}Y*_6D2;|(Z>I zM&LXBPIBZ9Pc8{zB^oNhL?i+#hHQw_shIr2tU;${LnrLX#HoV}_N z?~?zD&nqWHMZO6^QwPwtcAfINqHe4tXp(MlD%w4piF~d-Tbw$11?s$$n3AR639h<_ zH_SlMza{LRRdE4hKlx)or7y2!-HI*xv|{i1mDR<0v+rb22ZD10P-x97sc77)sgTQB zE|)m&1C#7J!JXsvFw|+5$o~>g#8~zxZe%%BaJ>d38TmDui6{Jj*NG3L80~PMRcXJX zm}n}(qPMZDbuv!?xr_|M6-(>C2*vSIN#(=umm!BHl0EYw6-G)C^jwI)+q8QMLES~x zKqk2)zOpcS>EXr7FoCswgEnY@QTMAMsX*noE{$CUN+t#PdL-aFBK8!L%ujC@x^je@ z>plMpcYgl=cNKIGsun3$ZTj$r)6Yf;(|e3eFUE%u(sv}5W1_?5D8zo(H&0Ho343p-+kp{=lv-`!0vl>^H;Y*L z$zz2lP*lQl#7JRw{YxUtVOjFI>+5f7Af5_A1Icqg6Qp6Mm;Bu58&w83Q#<0>;^xL3 zM_ysC+?Fcf=S1br>tRv4h(jL&5p3si7kHI@uNUecKp-aU5oyVZXwIR?0h{Fb4cCo6 z@qm^BBf#xyhbB~LC~uNJf^FaBF7C{SB*@ZBf*Rw$%%6{OmmYPF*0}3_r4fbGUh5IH zw|L~{sJ>FdJJQ!5x8knXGPV&6I{{U8sDL^xET?D65WBUbW|Ri0uD^4`&#I83OjomU zFw;rqS#YeaK5Va6pu4?begdQ{9S(ySryk`7K>*`LYXEM}VMF>|+*6aFi4!V#{D$Sr%R|2RtZ2>?FqM16CR=Gjh9Cs+GuA$0mw@ zH(&;8DTuWp62io~UO#=mF43L?>s;xl&|R}HY35=Dymm#WOczzDMNfZksTWsD2e5&? z5%*zUUhI6A|EAbHz5OYd*sOpBU6+VJ1zssqF7Q=qgV-JLk53;>HxVox7&4dKrf1K`(i zhajHu1Q?ECy=Ft$Xg1dLZ+p80}37P|{1KBaVAF|=Zmk`==4JMxFCAeePGb>nTpxoa7za)!?*L)7%D+aGwi;`G@MUi$X;`=1C&r?3ubyi8OUcC4dBmp_4aQ z)U{r=1*Tgx1UF^^?bg2FK*PzaPUqqSb2v-QC1atAVC^g{j#Dg@A(tK;i$Gh1s6)BD zJc(2!b16QANnQ51$SB|F_8t(+e^6N$f^sQ9B6VMf`|YzVgEo~<0IiDlW#Cg~pIBBf z038^ci&v3Pm1|)|0MAxbr$Y6~QvrE7Lz|9FfOCk5-oZ3KDqmo#5j+Mq2&( zuiPmv?(cg5-p2s-bnm;n>Q|DA3v=%;3G~xLWf~7;dp!P@$_QawQNDk$-x)LRj~D!L zd0;rtok6f36cHn638Ooi-9#h@M6d&1Zj2LYG_4NkiJQ8S24q7EDgDfN#Ra4?3)FfM zC-U;`#h0kt&7T|mNZgGCi}7!Ri=&0et-#OFp&F8war3muMTULP!Uo(Y`Yx-mF<+Ge zb47ir$WBK$QE|mhc(o2Cv}8NUn^sCo*L|ZoLpR)s`+rs5G(Ulgu1!`SMPGgfiyp9C zYaN_OtG`hjFwu>co`&d7!3P-n)Eqf$)C#Sd4jAup(V2ht_H(euH7PP&x3A%YB127o zqI}4zW$tfou6gVirzgv3GkW<`c3ByZKSSrYpQjAE@4c7J9U-wzBM-z8w5(Q;0r0w0 zk8CYbyQp$|mn#qE9-S6hP~lin7frsCP6a~xC@gdx8GsR$!Fy6mp~(@RV0a~nKL6-# zjZRDH++Kpwv6s7;prwVX1h3~b$X1A#vof*p8K;ahiDbDE2e_=MAf(EkYv*B+(o*_O zg)N0j0wx;NsoJ5wTx zofBd_WHtNrW-9`{rrf65go1`y9qNQ4& z%RiK{okpATTH!?jy7cY8H5)2K(V-z{Ly411O zD~v?j*1ids9ka+Lpa((DDUb4Oh~$>u^8)29O4JGK;<=GX@+GkiBx}Vyo9_4k_J27R zrBcTzF%qb&x=Km~tw6WLmo zQP{Yt@J~=GzLLR5I1|RkE5DT9KKulM(B>srlb#H@7`l<#V#C@mIbX=+1(XmvJseG2 z!HJaLj~aOp>q}hpx>i*Y2w->&kWdQh%d7};V%N5I;`>iRPi4aYPV1sCK%>WDxH(tPsnD;mxuL7aC*jgRXb z;?^xFnR8Jn>~yBwjQ;JW}ih#9<~5&BLF&&j48{c&4N_@>-F6^OrVm zk$iOeKVx4!2vN?8+nBsN@G@4)HcL_p8%OX(Lu})Gs2_}*&$`b_K}<+F!4aLUrCzO+ zn6-Kgfbf3p4lr$LkwnD&aD{M&U!0Y&ZsPi6qOhJ)w*rSV*cnt^wV)8cOh_Uk5Sv(j zCyW72mNAPu{=J#`%;#is&q}XO0Et)LW~q+dX~cP1_{K(}*D8QR16wUfz*S+Vcm@tqF?cVMbP?u@}ebN5$#4O@TyUl@!~%xy^$WFRqq2>-lIzt6R|j}*gH zJ1Ct8UQ$-@Rr)`TY0y}MIuD%a!Fig0N80@o42+b!(aoBc(Vum{xgID-5Bl;(mP0N4 zsRfCxx=wYdE0)F@9lsV`-4C4)!2WgGyM7<8Y|^-~?{XG7Spi2+yFM`!Vi1|XpUUz4 z%dPm*4Vjm6sq7lSufs|-tjep)w|fzz{x40;hA}|W6F2p4A#q#dz&a==h*)8 z<92YjLvw+g-8QZCdxl-8snw{DXPC+|<80j-)EUAS+y919EVT)Wr$=Yy58>2xiPmvl zG4tPiBjLlGCM9#50_^Fx|AiqFWD(bOW_>M9$|w$H#OQ(>H=X!p{@8Z-_hS&gy5AcS zasTFl2#dtUP)s&nt+_y{POT?>!}PYvu%QIrU&+MCK>{^^>5-<0L)4|-Q3I9X)-Zl3lWZBj{(%TCb1{ru*#)m zJ(4ol%T6L+y~Ql9-cGLq$5;msU%;IOS;WJ%)0YikNX5}=x^=e-7lJyGt!og z#ngk5dd8=Wbz*3roq$nzBU@5 zvuxl}`&u5?xAC+|E>0f%m{wE-Ew_G7v1i)-YNa%NZfu(qsy{=Nk0T;5J3 zI!Yf4g8SSCw!c-=eSzw++ZmD3P@b5g!V)VLN(^b%Za>vL#^B8LK;<9;cjUn)dw*a8 z1$A4BGp&)n2ot-17Sl_|{J!av=C7(pPmRZ*Hs0vtGB{ZWRl zkxHI3FP#MKhhWLW7=Fh|ED~CeeFYXQ_nNGgZ1U0)|5Vj!KjbOHko1}foHg}QJxb_Q zRAT$MoX}YUj9$QU{hsP-(4yv}uyV8h1oChh;SG#cYY#c)j2K{qsMN`Qj$RL6M8@xj z|2Y7Ffwz^c!vy1-B+iHNQw8QyI#$8}BOFAv=e{&XOGY1G8zWt(&-RZ6i8K7OS`GKD z^bxE`y+!n_aYtEHq2}u5V4?QP1od9f9alsB;X<4?U8(T}p*Nzz1%IZMeT_Rjp~!!D zO`Y8K?Cdwi8BoAXCfxc)*~YO^O^!-CYheh5unJ7!*uKy~ZePe;|1n0l<{hNeu!Veo zCsG_++Zkngif|%zU;*ST?SQ2H|3`6IEGD-*LrOO(>v%edNjxB47Sbyt-Hn-j#u?%vR`fu9jvvqFi!hN z&)!Wl+xwn|rEW4T@%>9C1qzJwGn+>O9!gYaQOE3uJ~173w}d!&rRi-rUb82xNW0-@ zPb3oxNkU~^-E$!EUe(G4PSogc@0aqAOX;aU2u>Q3^x;4-Y5T(%aoZT2(~-QNY?@K3mD zs}d_fZ(ZUo-fP5XHAGW_KCiO_z6lC<^PvSY&gQy$!l+2)@e_RsH1n=?V-G)5vD2cn zqH1vyhmC>90<=NMgX?DNM!*Jl05@{&5k4G-=x84nYl43!IQ+j+z%tPB;677N?nSRs z4EgzNU#Bur$=10)cn(;8S(UpLFg!wA(7N3!x}=e{jfh~Ss!d*-4^Cne801cei#iRX zP;}aU#fIRL33W(}fKQ@Hn^y3(EyIw)LB*;1F)V93>kh;%!ZL!sZpd7Euwh=;jiJ&H z5SpZ-%`%_AAtYY-Yufi!JuKHTz29)d}}15+ZdxrFpHH+{(^{H1^V zwdh5;8Jg5xRRew3|FTq-L8sm^NaQn$6>se;@b_#4_M*zx$1}lssJk?tT2r7$LD5>}i>6ubE)G4TEh^$J9Ra&4T(Pk?Q>)T-wt{99ThJ)=`LTNOJ? zmu;Vmgk0VxNDxMk;x!$*M23iFex8Sx^WgvAV-&MolsBkLn-fxCORX(RZRPoxAvJ0; z65CCV;8DHLgy(#KV&BW(9jGp;|0v0C$0K-majJtz$|G;#8_JWq7%SM*C0S%zG1f%sAm^Y;;${>Vnjly0F(ab(9p1Q*H?mH$613_8<-uZ$)?? zIQT3h+=VT+I=kEpK#-?{)<5BvFWHN9A(6CaM>!&Dn=x@f0gwOF2tMg`h~L#XR2<_U zQ;p8<-ME;*% zMO925e!Iy1!U3s=0NdL+}Z-f!9qAQ&ct-q>DCX(fQZF2&vC0pykY(C{)z0= za)OKsCohRejlHt0ReFtRAtS)`syV(F!``Sjf(X>TVa%TTb>NA5T}-2~5@44-Ef)Fv zxs_*MeCphzTx?9tS6JM2Biwz~53%xe1BLAvLp+ru2pRkROoJva#wWB9B(cD2_t>Cz zz9JY5|DyFeWy7D^NDhbweT0DUeLKN4u1%MMqk976l%;7lMhp8cD(+v|EtxdCA}^R* zgV{7VVXASG<#{-0nxMADSUbyUiG!cTIw7nhhpAakx8B~zsSfp@SZ!RB=GY+s z{6P2t1l~6`FY@w(&Ss%IALFi}dd-3|dOk2h>D=r6XqyPa(w*@xYpl5Ylqasst5?mU zq+^)a6H<}(jJ_?(;ufEpX{H%cq(@24d0p|o#;AnxP4DSel-}P@_|qWJtF!yEl$6iE z01X(NRZ*U=q=_jJATbi1bv#vOL8`#I#J|GS>T3wWy!nLC@O6IWb88 z|J~d#gbg-R26d{BRvdAfT-zQQ=dQhlG2dJq4%9Sa7eIbVxqq65hN51!xCPdzq}TTM zodAE0nCO?M)p5PCl%zT*9!HE$$_fUcqt7(NIbKeH_2l6$(7~c&3&){L^c2aDL%m8* zSq((XReu$Y)8H8%0tn?)Yj$8r_n0e(u#h|`#b_S`u!t?k2Uc(9Ain9%KK-eGJADuH zQZjcwExB2@kY=3l%9cBmrnIhAV%y|L%z)tv)gk%h49ydJ zp{m4gKHEIh?*Eejy6jLI=FXW4-sgMeEtOL?FkV0laNMSt@}aaD5*x zjY&EA@JkLQ0y|_Wt+safWi3Kxs&nFyTbi2b4*{xHlS!_^cXWdTFez39>Ty;RZp3>HQN!{a#8IKn5{kIuAb@w<$SpJ+pN)q z$o5RQ=QP(NE~eC`rNd=geL|7a$2t~vm>M|S`DH8;+W{{ll7UjXLUgfSs%=eZk-W=y zt-bAocZq3=hQ(4#`w7kj1A?pKsu!5Qgcb0zTzD3qGJ7XES*I3FCL?2?kDUr9i!0C} z$&B2gG7-INVKJWh|3dotRbWsPH?LgI>0D35*x?>VO1UTxXG3ZJR20D*Bt1Yt*>3ir zNLGrMpqqXAp!2wm`}mG@y1xHnDsyfb9HXivs8p+eGK=l=XUfLW;m|xMAYJ`;z*R66 z1iaaIm2Bb5W0Lc5Jl=9US%#dga`r$C=_Vrzg$?4;6R|1-jT5;?)m8O(lC|`{_{x)N zi=xw2821rVv6(sMqaDVTA?m)I(P_FjDeZBk-FtlyiZW0wSu);Pp3ZG%ax}Z~Ss}*n9Ew8fH>R99a zMT>A14%tVfR9hIuk3uXEClvygeM33q2}@jHfqQx*zzhVA^C(=dU}xk-4>68FGGZRa zK@``?*N&azEi!by3^Pl5o*pEQjdBbMMZhh1SLOA3!Rb-%Q&X=`uvLwmgtEGEpKEQN z)8`9DI%;yyCQ_B`++-4gPeE20j`|N&BeInQZtRG>|3m1tzEYmdWBie<0LV8MH6Te+ za~IDNt`6eoTtpw2VBdn>LpkbohpNmARCsDA%Wcum$dRbLP;DHrKP;W-mYV$P}k+ zW?783Og)bbT%DKTEWnudcRVA|Rfe&*+)aGWxmV{U0V1`NOpU2aiq-Z#td!iYGd(FQ zKoVivx+9Dc)BCV#Y3^^{{{&jYhUNBxH`&Cx<5M*=v&9O0IY82zXv>1;R}u3=;N83s zj+`m7D<_lDokD!kFSF#BLxMC_pvemdSVN`ZUc9q7`?INwr6S^xj&fk&;Jm^=vo4mn zdsRchqij|t@jn${yQ5bRd!;&~llNV$7d+*qt!<|m7%dva`)iTSXQe>|gX@_a;LVg6 zQmV(hDBcKz2~U_9R~TU%zj1?0gbvGFQk=EGse|$irb*H|yO*>*`Rq?aK5t0xDY?ha z->-4!>onITcd3mk1;e>B%|t}Nl7;aD(Mp}K_?!T6;$9-DB+5PGw9YaC#y0mm8x$RJ z930GZPwqgpsE;xDv)nNGb?uM57_cq%owkeN2ZUmnGW3qWOC*0?wK-YFKVMi<>Sp30 zE^N}Gdyjps_}S0j;#%d0pbz-nO6qg9DO(`MF8ay~cz|+?xQmpDl}xgZ?)g*^OT1}j z=s$B!9ML$-BVXA0&H6*zqKIPdfR^@IC#LENQqd`AHo1#o^GN#OV}ly5 z8RWh%8K5WG4a@`fHU;xyTT9t;S-042z;Uqr5&#Zd1Kmw>P2&ntz@9+grBrIfCN>2n zZ<^H@_@F*{577GTNG(?5I*ZSRd?`C-p*r%iQ~D{XJ$&td*~OJ>pgSIAQwEibfr75U1O zD%V;Jy8>H4{qd2o^&LW4xEN&JkiN+A=smDtA-xnrDvu;=-3=9WxPZ2La; zRIi%dqasRXFM3nUy;u-i&(^a6(0f=Biok0$Kz>eqr>l!v5QfU00fE zPIVWU%-{?S2(VEmp(f@Qsq*DU4bg@dO9e0b(qJms17}w%RG-LOHVB*X`!`#zqPeJ( zLIX2}(jcO9$A61YV6hXmCwu`LGmxkBGLXY#!L~8X!`gh7cLn|2*Q4)zbr-@S!|GxT zEgH_HmG*ftJj!D)qVBH!?=1Mn6xsd=b_(XcQx=wAS{g*^@>+#cnN?T%-pa2F>b9;y z-AxgK7u|0~bD9qS+cg*f8KS9YJ{1S<9Ri2B$gb*TCeeDg;|=xBvyqE-)CFsfZC{@s z3&WgO=j?6`DyV}#K%6~uG~l_REMv}1#|u5a#xYfsTtNYW_Wy5fn8j4!Bh-tuwON?W zHChl5NDKyu)Zgl=<@uHaK$3S=4_80j1Knsx)?cY0S`DyF{H@~6b5*{Ve|E}yH=lfS zPx1>4Bwpi!Y}W9V6N$(IocT|QeGFtycB3cAdMT6F77|#n9z~GWUO*$xG+6RQ5IDAf z-CVph*p#=h|EFnXUZ6ysa*USu1gfm`w(ibrT6;;WYx$6(9S3kw_nKS28+m5n=FsYt zim3w10GwB}4SK;E_6*m+sCB^n1%fatf2{O&oJ7BVm&d1u1dk@t`mB_NsIChZH5cn8 zd#no<+{t&T^kGAnF^#xuiw$%mKWLR$khE0-m2(;{59>z$U;dk;ckG zV_G^d5r1vV3E9ovH^01dj?Xuj79;0}O`Y;08zWq^cjaMb@spOEJ9{9^WQ3f+#N^S^ z=-Ei%Ejq$OHj1S8}1VbaTUur znJSn_#N7d1)09#g-sP{JPoEcqBT(neb+HZr{g&t*iMa)``9msw($V}cInJ3PN)@e#pqAq zD4zbv-=IIijPhSsK*la+l6JnC>KMPni6CBmZ7qJ}q5>v;-eA-8D6J(1^1EHpGvYH} z<0I-ON+I1x9k&mJFO*fD!_3Hpydp``N>Wsn+r_;l4j1<#PL~uvZRBQ-e|>53>%KDFO0ZKm^A_OXqWKrj%$w zK0XM1{0!Ot-YF`7a6up?_qZ=3uj-+$HT~#~v5)3>Lsy+5&gm%B;qp#&+2l=#M6Y{A z=qnb_GTSU{0;NJn%@X`#z}NjHX|dX$oZ4!cCw9Z^xtB%Qlgc%f{-o~I2l}o?HW2G6 zO@|0SO@BuxR@l0*X}A$xpZ8SQm9;gpFbt9j6Mx2AUO7j{UsUncQa3L&8_N?dZ?Vjj zR&JsWCIF5AQokBA?hG1KUWd?*i4zCOc5d*IB2N$Y>jRt8j#QP0a&5Vx6UAz)9$P60kt)%y+P}o2RyS0Li1Pt1> z^H{)#;7jN@Bf-tn=(B-)L~Rd-h*oVZ5rXYu?nyD zc8`TT|38rRT|i3Z28vy5 zW@hw2I`=L5{Xry0@!=VKYXz@k69WhCwcw)^>2wGRK{?1fT)6FN6=EG? zYoU@}X2ckb_ZcUwg;xXq&g#gi5ePb|Su5BpnEmBoyC`n%N4*CV1V6j)@M^iQ6C!yHWZJB6O`Xt8-xxkaEtI z_q$;yDAszkL0@Q%)4M&rON-|IPyW}hgO>tF{k!L`5MNc6K_g=H;QQ24!bqx$dQhc3 z=(@<({;9idzH1yWAQ0Kmo%8m@rED5^t=lE*kxEUnSk5q_f=Q4IV z-`glN(-;h!rurOMq{M^^^B7bE7M+nKiC;0|p{a)MTKZoFyDmFx-CBTP|7&aiI@52X z1fJ+Y1fM=!p-#fXEj1*qkUu3fN;g@!XfeXEk037z$;Hw8;GJ3NBs{}-8upjc8$ z{zOWvtRk^IeCpqQYHLw1W68k~5Q&K3*6o(>w(+%%#_XSZFi>j@0^mt$sutrLl9(kG z%=8mqgD9}Q6|K5<>xri!p1Opx&=g;WWIbytsp1_IeK#5%A2hk4A+u9@W>$7`au9Bo zxRC2{q{mRXSef@%f!t;S(J)_zCHzYq`cH3oSu5ei7i{U?JgJio#?J*@pji_*k*P}s z$o94=^3LTeJn}~xmLSmruy*1ZiC=hc>pBz6Q-L{8~Ugky|bhDZ_aokLO*^xWXh!Zm=3I}4p13RGCG-~1LLqbJE z)q}D)cwBNktP8`L_BQc$&jsJz0i!ge;z_S9b%|f`>Ry};I-TV2%#f5E+e_bPVJOAL_6)dkh!8Qb2D)M?7kiR<6?i73YC`)3JfJ}F=|;jI z;r>CG(y={_4|#($aVMU5y-?jowb^%lWUwnq<^-SX2p{8`91?cif1TjFmBp?sFJw1& zpc5}0_@kehiPlB-ntx@JRo}@CK1B$%o9g-K7WizCjWkj2s}DD-*aJ2sjDYSZIoj;ijH4X{Qy>`0(!6lk{w?44qBD+pnXbEs6GsX|QdOYGB&e zS=Ew=kE+gw>0{t6rvEIa`30BG;wd-naUb~+7;&@0;Lkv6Sz3~J$A8zawez%jvN)d? zfhGf{&Vv!{U?=5Gi$evyDuTaS2%US37KKHqb37+rDo%4(Kk{f^o>5g&|D+^%y-1h{ z7CUdrVExG|Rf)7_0enl5N?+6&>0FP)yxQRb0VWF3V)uxt?2Rl znoeSLF5nV2T=tFQE0a#i4WtzzjpYHqGH?2utmJKn;;(Kq@il-a}$$3!MXriOk3Ulkj)%y#rpdUjm;ZS86{gT!wdRz!SHL~?qWM;R#~Xw zn<0I*F~?c(e((^HW0nVB!k<_Xui^82Ts*=LKpK)6YYw$K-lJMsEUu&)P!&;<-;8PS zgWz-aNyr}WH3lB;sb=RjLq3fg1W{xD|2O{56J(_&jbeQZ!~#CYiYgQQO0iD{bjn(hpGbr(TH+iL%%)v z{qbh$f})!ubaD8wAmH#>qGlL3G#7sy;rLV8mhCW=WN12~d!HubyuSPvCy$_mzTy=l zyb4*BO+?-C=&abYKlWoVBm}$;(hK^h8-5N`xsz(`_zlmNf>=htXD%WO% zj)(&V{f%|w96E_ihtPB_jFR4$;{EEyRM&m27ChnDyxw{cFj{deJUVA;iiwF;LO%)I z-*I-71;RxVh-TnwFPErbdNNV(R)JC8UP{JW&{>Hevaf_Rr#>ws%r>Z9-!Yvyz*g?g zqXSS8OY>4G{YudS((Ba}4b|`!*>u2JptF6Nn{$=hG97B9U{f74*YFRNgI0uhZhPm^&NK!|V1xNaHYdH2i3)z*F*j%9_^I&2 zBCWlW4>!W)B**y3rOnaTDxvSb+(5sMVFfeKt90Q;ChV&Nv|*}brJ6#b8>t)EXDgR--i5G z$ie-?20F(0zM0yI>C8~byKx3S4Ow=U_99y26d0DLWWE_H5J+b5SV6u9-BPXMdd;&| zb^0#Ae)Rt(4sA$38w7-?M^rs+*@n>nE}rkxO#yR5JS7nU;xMrurMH=K2Uqd^vyE7H)P+B2aM zs5GpC$JVVue~_n^+48~E@`uf3Rz5j;pJ>J545ZA5DRwB%{k8iQlJfb!RFTD*SG;0n zD!W59%s?6aZY~T*!tikEzt#)`6n>EzJsxn=mX!Fiocl%0Ay&^31-{e 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

    LWjXfjx{K&3}afCKxkGj}jk&;$-3*;`B$8NB@ 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̢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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.mq5 b/BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.mq5 new file mode 100644 index 0000000..8cc6f1f --- /dev/null +++ b/BKPS/14031218/Experts/x-saherelm.x-121.smc.ea.mq5 @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: X121SMCEA +// Description: an Exper Advisor which used Panels +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121SMCEA" +#property strict + +// +#define ShortName "X121SMCEA" + +// +// Imports ... +#include "../X121SMCEA/Experts/x-121.smc.expert.class.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Symbols ... +input group "Symbols"; +input bool eaMultiSymbol = false; // Use Multi Symbol +input string eaSymbols = "EURUSDb,GBPUSDb,USDCHFb,USDJPYb"; // Trading Symbols + +// +// Signalling ... +input group "Signalling"; +input bool eaAllowLong = true; // Allow Long Signals +input bool eaAllowShort = true; // Allow Short Signals +input int eaMaxAllowedLongs = 5; // Max Allowed Long Signals +input int eaMaxAllowedShorts = 5; // Max Allowed Short Signals +input bool eaUseMaxAllowedSignalsPerSymbol = true; // Use Max Allowed Signal Types Per Symbol +input double eaLastPositionProfitForAcceptNextInPoint = 30; // Last Position Profit In Points for Accept new Signal +input int eaDelaysBetweenTwoSignalsInBar = 12; // Delay between two Signals in Bars +input double eaMaxAllowedSpread = 25; // Max Allowed Spread for Signalling +input int eaMinRequiredVerificationForSpreadPass = 20; // Minimum Spread Verification for Signalling + +// +// Trade ... +input group "Trade"; +input bool eaAllowTrade = true; // Allow Open Trade On Signals +input string eaStartTradeAt = "02:30"; // Enable Trade on Signals on Time +input string eaStopTradeAt = "23:30"; // Enable Trade on Signals on Time +input string eaCloseAllTradesAt = ""; // Enable Close All Trades on Signals on Time + +// +// Risk Management ... +input group "Risk Management"; +input double eaR2R = 6; // Signallers Risk to Reward Ratio +input double eaVolume = 0; // Static Volume +input double eaStaticBalance = 1000; // Static Balance +input double eaBalancePerTrade = 10; // Balance Used in Each Trade +input double eaRiskPercentPerBalance = 0; // Risk Percent Per Balance in Each Trade +input bool eaDynamicRiskManagement = false; // Dynamic Risk Management +input bool eaUseDynamicVolume = false; // Use Dynamic Volume +input double eaDynamicVolumeStep = 0.01; // Increase Volume Step +input double eaDynamicVolumeBalanceFactor = 200; // Balance Factor for Generate Dynamic Volume +input double eaMaxAllowedDrawdownToOpenTrades = 3; // Max Allowed Drawdown for Open Trades +input int eaMaxAllowedSLToPauseSignallingPerSymbol = 2; // Max Allowed SL for Pause Signalling Per Symbol +input int eaPauseSignallingAfterReachesMaxAllowedSLInSecconds = 10800; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds + +// +// Protection ... +input group "Protection"; +input bool eaAllowHedging = true; // Allow Hedge Positions +input int eaMinOpenTradesFroHedging = 2; // Minimum Open Positions for Hedging +input double eaHedgingMinVolumeStep = 0.01; // Minimum Volume Step for Hedging +input double eaHedgeingMinRequiredProfitPerVolumeStep = 1.0; // Minimum Required Profit Per Volume Step for Hedging + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = false; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours + +// +// Define Local Variables ... + +XC121SMCExpert *eaExpert; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XC121SMCExpert(); + + // + // Event Handlers ... + eaExpert.OnSignalEventListener = OnSignalRecieved; + eaExpert.OnDealsChangedEventListener = OnDealsChanged; + eaExpert.OnOrdersChangedEventListener = OnOrdersChanged; + eaExpert.OnPositionSLEventListener = OnStopLossTriggered; + eaExpert.OnPositionTPEventListener = OnTakeProfitTriggered; + eaExpert.OnPositionsChangedEventListener = OnPositionsChanged; + eaExpert.OnPositionForceCloseEventListener = OnPositionForceClosed; + + // + // Common ... + eaExpert.MagicNumber(eaMagicNumber); + eaExpert.Slippage(eaSlippage); + eaExpert.TagPrefix(eaLogSuffix); + + // + // Symbol ... + eaExpert.SetSymbol(_Symbol); + eaExpert.SetPeriod(_Period); + eaExpert.Symbols(eaSymbols); + eaExpert.MultiSymbol(eaMultiSymbol); + + // + // Signalling ... + eaExpert.AllowLong(eaAllowLong); + eaExpert.AllowShort(eaAllowShort); + eaExpert.MaxAllowedLongs(eaMaxAllowedLongs); + eaExpert.MaxAllowedShorts(eaMaxAllowedShorts); + eaExpert.UseMaxAllowedSignalsPerSymbol(eaUseMaxAllowedSignalsPerSymbol); + eaExpert.LastPositionProfitForAcceptNextInPoint(eaLastPositionProfitForAcceptNextInPoint); + eaExpert.DelaysBetweenTwoSignalsInBar(eaDelaysBetweenTwoSignalsInBar); + eaExpert.MaxAllowedSpread(eaMaxAllowedSpread); + eaExpert.MinRequiredVerificationForSpreadPass(eaMinRequiredVerificationForSpreadPass); + + // + // Trade ... + eaExpert.AllowTrade(eaAllowTrade); + eaExpert.StartTradeAt(eaStartTradeAt); + eaExpert.StopTradeAt(eaStopTradeAt); + eaExpert.CloseAllTradesAt(eaCloseAllTradesAt); + + // + // Risk Management ... + eaExpert.R2R(eaR2R); + eaExpert.Volume(eaVolume); + eaExpert.StaticBalance(eaStaticBalance); + eaExpert.BalancePerTrade(eaBalancePerTrade); + eaExpert.RiskPercentPerBalance(eaRiskPercentPerBalance); + eaExpert.DynamicRiskManagement(eaDynamicRiskManagement); + eaExpert.UseDynamicVolume(eaUseDynamicVolume); + eaExpert.DynamicVolumeStep(eaDynamicVolumeStep); + eaExpert.DynamicVolumeBalanceFactor(eaDynamicVolumeBalanceFactor); + eaExpert.MaxAllowedDrawdownToOpenTrades(eaMaxAllowedDrawdownToOpenTrades); + eaExpert.MaxAllowedSLToPauseSignallingPerSymbol(eaMaxAllowedSLToPauseSignallingPerSymbol); + eaExpert.PauseSignallingAfterReachesMaxAllowedSLInSecconds(eaPauseSignallingAfterReachesMaxAllowedSLInSecconds); + + // + // Protection ... + eaExpert.AllowHedging(eaAllowHedging); + eaExpert.MinOpenTradesFroHedging(eaMinOpenTradesFroHedging); + eaExpert.HedgingMinVolumeStep(eaHedgingMinVolumeStep); + eaExpert.HedgeingMinRequiredProfitPerVolumeStep(eaHedgeingMinRequiredProfitPerVolumeStep); + + // + // Alert ... + eaExpert.SetAlertEnableAlerts(eaEnableAlerts); + eaExpert.SetAlertLogAlerts(eaLogAlerts); + eaExpert.SetAlertMailAlerts(eaMailAlerts); + eaExpert.SetAlertPushAlerts(eaPushAlerts); + eaExpert.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + // Reports ... + eaExpert.ReportNewMonths(eaReportNewMonths); + eaExpert.ReportNewWeeks(eaReportNewWeeks); + eaExpert.ReportNewDays(eaReportNewDays); + eaExpert.ReportNewHours(eaReportNewHours); + + // + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + return INIT_FAILED; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + eaExpert.HandleOnDeInit(); + + // + delete eaExpert; + + // + ZeroMemory(eaExpert); +} + +// +// On Tick Handler ... +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Event Listeners ... + +/** + * Do What we Want by Specific Signal ... + * + * @param signal: XSignal instance ... + * @param conditions: XStrategyConditions instance ... + */ +void OnSignalRecieved( + XSignal &signal, + X121SMCStrategyConditions &conditions // +) +{ + // + eaExpert.HandleOnSignalRecieved( + signal, + conditions // + ); +} + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.helper.mq5 new file mode 100644 index 0000000..f97ba86 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.helper.mq5 @@ -0,0 +1,4464 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121Helper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Helpers/x-saherelm.x121.x3ma.helper.mq5" +#include "../Helpers/x-saherelm.x121.xatr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xdon.helper.mq5" +#include "../Helpers/x-saherelm.x121.xhk.helper.mq5" +#include "../Helpers/x-saherelm.x121.xpv.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xtrend.helper.mq5" +#include "../Helpers/x-saherelm.x121.xvwap.helper.mq5" + +// +// Inputs ... +struct X121Inputs +{ + // + // Props ... + bool showRSI; + X121XPVInputs xpvInputs; + X121XHKInputs xhkInputs; + X121XATRInputs xatrInputs; + X121XSTRInputs xstrInputs; + X121XCHEInputs xcheInputs; + X121XDONInputs xdonInputs; + X121X3MAInputs x3maInputs; + X121XVWAPInputs xvwapInputs; + X121XTRENDInputs xtrendInputs; + + // + // Constructor ... + X121Inputs() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + xpvInputs.Clean(); + xhkInputs.Clean(); + xatrInputs.Clean(); + xstrInputs.Clean(); + xcheInputs.Clean(); + xdonInputs.Clean(); + xvwapInputs.Clean(); + xtrendInputs.Clean(); + + // + ZeroMemory(this); + } + + /** + * Set Default Values ... + */ + void Default() + { + // + xpvInputs.Default(); + xhkInputs.Default(); + xatrInputs.Default(); + xstrInputs.Default(); + xcheInputs.Default(); + xdonInputs.Default(); + x3maInputs.Default(); + xvwapInputs.Default(); + xtrendInputs.Default(); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + xpvInputs.IsValid() && + xhkInputs.IsValid() && + xatrInputs.IsValid() && + xstrInputs.IsValid() && + xcheInputs.IsValid() && + xdonInputs.IsValid() && + xvwapInputs.IsValid() && + xtrendInputs.IsValid() + // + ; + + // + return result; + } + + /** + * Extract Max Input Length ... + * + * @return ( int ) + */ + int Max() + { + // + int result = 0; + + // + int xpvMax = xpvInputs.Max(); + int xhkMax = xpvInputs.Max(); + int xatrMax = xatrInputs.Max(); + int xstrMax = xstrInputs.Max(); + int xcheMax = xcheInputs.Max(); + int xdonMax = xdonInputs.Max(); + int xvwapMax = xvwapInputs.Max(); + int xtrendMax = xtrendInputs.Max(); + + // + result = MathMax(xpvMax, xhkMax); + result = MathMax(result, xatrMax); + result = MathMax(result, xstrMax); + result = MathMax(result, xcheMax); + result = MathMax(result, xdonMax); + result = MathMax(result, xvwapMax); + result = MathMax(result, xtrendMax); + + // + return result; + } +}; + +// +// Conditions ... +struct X121Conditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double maBuffer[]; + double rsiBuffer[]; + double atrBuffer[]; + double strBuffer[]; + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + double upTBuffer[]; + double adxBuffer[]; + double adxPBuffer[]; + double adxMBuffer[]; + long volumeBuffer[]; + double peaksBuffer[]; + double valesBuffer[]; + double strUpBuffer[]; + double downTBuffer[]; + double strDownBuffer[]; + double vwapMidBuffer[]; + double upTrendBuffer[]; + double x3maMidBuffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + double strPriceBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double strStateBuffer[]; + double vwapFastBuffer[]; + double vwapSlowBuffer[]; + double xhkSMLowBuffer[]; + double x3maFastBuffer[]; + double x3maSlowBuffer[]; + double downTrendBuffer[]; + double vwapPriceBuffer[]; + double xhkRawLowBuffer[]; + double xhkSMOpenBuffer[]; + double xhkSMHighBuffer[]; + double xhkRawOpenBuffer[]; + double xhkRawHighBuffer[]; + double xhkSMCloseBuffer[]; + double vwapVolumeBuffer[]; + double xhkRawCloseBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double vwapMidStateBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double x3maMidStateBuffer[]; + double vwapFastStateBuffer[]; + double vwapSlowStateBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + double x3maFastStateBuffer[]; + double x3maSlowStateBuffer[]; + + // + double rsiSlope; + double strSlope; + double atrUpperSlope; + double atrLowerSlope; + double vwapFastSlope; + double vwapMidSlope; + double vwapSlowSlope; + + // + // Conditions ... + + // + // XTrend ... + + // + bool isTrendBullish; + bool isTrendBearish; + bool isTrendSwitchedToBullish; + bool isTrendSwitchedToBearish; + + // + bool isRsiSlopeBullish; + bool isStrSlopeBullish; + bool isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish; + bool isStrSlopeBearish; + bool isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish; + + // + bool isRsiOverSold; + bool isRsiOverBought; + bool isRsiCrossedOverOverSold; + bool isRsiCrossedUnderOverSold; + bool isRsiCrossedOverOverBought; + bool isRsiCrossedUnderOverBought; + + // + bool isClosedOverAtrUpper; + bool isClosedOverAtrLower; + bool isClosedUnderAtrUpper; + bool isClosedUnderAtrLower; + + // + bool isRejectedUpAtrUpper; + bool isRejectedDownAtrUpper; + + // + bool isRejectedUpAtrLower; + bool isRejectedDownAtrLower; + + // + bool isBreakedUpAtrUpper; + bool isBreakedDownAtrUpper; + + // + bool isBreakedUpAtrLower; + bool isBreakedDownAtrLower; + + // + bool isRejectedDonOpenUpper; + bool isRejectedDonHighUpper; + bool isRejectedDonLowUpper; + bool isRejectedDonCloseUpper; + + // + bool isRejectedDonOpenLower; + bool isRejectedDonHighLower; + bool isRejectedDonLowLower; + bool isRejectedDonCloseLower; + + // + bool isBreakedDonOpenUpper; + bool isBreakedDonHighUpper; + bool isBreakedDonLowUpper; + bool isBreakedDonCloseUpper; + + // + bool isBreakedDonOpenLower; + bool isBreakedDonHighLower; + bool isBreakedDonLowLower; + bool isBreakedDonCloseLower; + + // + bool isSarBullish; + bool isSarBearish; + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + bool isRejectedPrevPeak; + bool isBreakedUpPrevPeak; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + bool isRejectedPrevVale; + bool isBreakedDownPrevVale; + + // + bool isStrBullish; + bool isStrBearish; + bool isStrSwitchedToBullish; + bool isStrSwitchedToBearish; + + // + bool isChe1Bullish; + bool isChe1Bearish; + bool isChe1SwitchedToBullish; + bool isChe1SwitchedToBearish; + + // + bool isChe2Bullish; + bool isChe2Bearish; + bool isChe2SwitchedToBullish; + bool isChe2SwitchedToBearish; + + // + bool isCheBullish; + bool isCheBearish; + bool isCheSwitchedToBullish; + bool isCheSwitchedToBearish; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapMidNeutural; + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + bool isVWapFastNeutural; + bool isVWapSlowNeutural; + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + bool isX3MaMidBullish; + bool isX3MaMidBearish; + bool isX3MaFastBullish; + bool isX3MaFastBearish; + bool isX3MaMidNeutural; + bool isX3MaSlowBullish; + bool isX3MaSlowBearish; + bool isX3MaFastOverMid; + bool isX3MaMidOverSlow; + bool isX3MaFastNeutural; + bool isX3MaSlowNeutural; + bool isX3MaFastUnderMid; + bool isX3MaMidUnderSlow; + bool isX3MaBullishState; + bool isX3MaBearishState; + bool isX3MaNeuturalState; + bool isX3MaBullishOrdered; + bool isX3MaBearishOrdered; + bool isX3MaSwitchedToBullishState; + bool isX3MaSwitchedToBearishState; + bool isX3MaSwitchedToNeuturalState; + bool isX3MaSwitchedToBullishOrdered; + bool isX3MaSwitchedToBearishOrdered; + + // + bool isSMHKBullish; + bool isRawHKBullish; + bool isSMHKBearish; + bool isRawHKBearish; + bool isBreakedUpSMHK; + bool isBreakedUpRawHK; + bool isRejectedUpSMHK; + bool isClosedOverSMHK; + bool isRejectedUpRawHK; + bool isBreakedDownSMHK; + bool isClosedUnderSMHK; + bool isClosedOverRawHK; + bool isClosedUnderRawHK; + bool isBreakedDownRawHK; + bool isRejectedDownSMHK; + bool isRejectedDownRawHK; + bool isRawHKBreakedUpSMHK; + bool isRawHKClosedOverSMHK; + bool isRawHKClosedUnderSMHK; + bool isRawHKBreakedDownSMHK; + bool isSMHKSwitchedToBullish; + bool isSMHKSwitchedToBearish; + bool isRawHKSwitchedToBearish; + bool isRawHKSwitchedToBullish; + + // + // Complex Conditions ... + + // + double cheMin; + double cheMax; + double x3maMin; + double x3maMax; + double vwapMin; + double vwapMax; + + // + bool isSarIncreased; + bool isSarDecreased; + bool isX3MaFatsOverMid; + bool isSarEqualsToPeak; + bool isSarEqualsToVale; + bool isStrEqualsToPeak; + bool isStrEqualsToVale; + bool isX3MaMinBreakedUp; + bool isX3MaMaxBreakedUp; + bool isX3MaFatsUnderMid; + bool isX3MaFatsOverSlow; + bool isAtrUpperOverPeak; + bool isPeakOverAtrUpper; + bool isStrUpperOverPeak; + bool isStrLowerOverVale; + bool isBreakedUpPrevSar; + bool isBreakedUpPrevStr; + bool isVWapMinBreakedUp; + bool isVWapMaxBreakedUp; + bool isClosedOverCheMin; + bool isClosedOverCheMax; + bool isX3MaFatsUnderSlow; + bool isAtrLowerUnderVale; + bool isClosedOverX3MaMin; + bool isClosedOverX3MaMax; + bool isValeUnderAtrLower; + bool isStrUpperUnderPeak; + bool isStrLowerUnderVale; + bool isClosedUnderCheMin; + bool isClosedUnderCheMax; + bool isClosedOverVWapMin; + bool isClosedOverVWapMax; + bool isX3MaMinBreakedDown; + bool isX3MaMaxBreakedDown; + bool isClosedUnderX3MaMin; + bool isClosedUnderX3MaMax; + bool isBreakedDownPrevSar; + bool isBreakedDownPrevStr; + bool isStrCrossedOverVale; + bool isSarCrossedOverVale; + bool isClosedUnderVWapMin; + bool isClosedUnderVWapMax; + bool isVWapMinBreakedDown; + bool isVWapMaxBreakedDown; + bool isX3MaFatsOverMidPrev; + bool isSarCrossedUnderPeak; + bool isStrCrossedUnderPeak; + bool isNewPeakOverAtrUpper; + bool isBreakedUpPrevCheMin; + bool isBreakedUpPrevCheMax; + bool isBreakedUpPrevCheLE1; + bool isBreakedUpPrevCheLE2; + bool isBreakedUpPrevCheSE1; + bool isBreakedUpPrevCheSE2; + bool isX3MaFatsUnderMidPrev; + bool isX3MaFatsOverSlowPrev; + bool isAtrUpperEqualsToPeak; + bool isAtrLowerEqualsToVale; + bool isStrUpperOverAtrUpper; + bool isStrLowerOverAtrLower; + bool isNewValeUnderAtrLower; + bool isAtrUpperCrossedUpPeak; + bool isAtrLowerCrossedUpVale; + bool isStrUpperUnderAtrUpper; + bool isStrLowerUnderAtrLower; + bool isX3MaFatsUnderSlowPrev; + bool isBreakedUpPrevAtrUpper; + bool isBreakedUpPrevAtrLower; + bool isBreakedDownPrevCheMin; + bool isBreakedDownPrevCheMax; + bool isBreakedDownPrevCheLE1; + bool isBreakedDownPrevCheLE2; + bool isBreakedDownPrevCheSE1; + bool isBreakedDownPrevCheSE2; + bool isX3MaFastCrossedOverMid; + bool isRejectedUpPrevAtrUpper; + bool isRejectedUpPrevAtrLower; + bool isVWapFastCrossedOverMid; + bool isX3MaFastCrossedUnderMid; + bool isX3MaFastCrossedOverSlow; + bool isAtrUpperCrossedDownPeak; + bool isAtrLowerCrossedDownVale; + bool isStrLowerOverDonLowLower; + bool isVWapFastCrossedUnderMid; + bool isBreakedDownPrevAtrUpper; + bool isBreakedDownPrevAtrLower; + bool isStrUpperCrossedOverPeak; + bool isStrLowerCrossedOverVale; + bool isDonLowLowerEqualsToVale; + bool isVWapFastCrossedOverSlow; + bool isX3MaFastCrossedUnderSlow; + bool isStrUpperOverDonHighUpper; + bool isStrLowerUnderDonLowLower; + bool isVWapFastCrossedUnderSlow; + bool isStrUpperCrossedUnderPeak; + bool isStrLowerCrossedUnderVale; + bool isDonHighUpperEqualsToPeak; + bool isRejectedDownPrevAtrUpper; + bool isRejectedDownPrevAtrLower; + bool isStrUpperUnderDonHighUpper; + bool isStrUpperCrossedOverAtrUpper; + bool isStrLowerCrossedOverAtrLower; + bool isStrUpperCrossedUnderAtrUpper; + bool isStrLowerCrossedUnderAtrLower; + bool isStrLowerCrossedOverDonLowLower; + bool isStrUpperCrossedOverDonHighUpper; + bool isStrLowerCrossedUnderDonLowLower; + bool isStrUpperCrossedUnderDonHighUpper; + + // + // Constructor ... + X121Conditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(maBuffer); + Clean(rsiBuffer); + Clean(atrBuffer); + Clean(strBuffer); + Clean(le1Buffer); + Clean(se1Buffer); + Clean(le2Buffer); + Clean(se2Buffer); + Clean(sarBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + Clean(upTBuffer); + Clean(adxBuffer); + Clean(adxPBuffer); + Clean(adxMBuffer); + Clean(volumeBuffer); + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(strUpBuffer); + Clean(downTBuffer); + Clean(strDownBuffer); + Clean(vwapMidBuffer); + Clean(upTrendBuffer); + Clean(x3maMidBuffer); + Clean(le1StartBuffer); + Clean(se1StartBuffer); + Clean(le2StartBuffer); + Clean(se2StartBuffer); + Clean(strPriceBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(strStateBuffer); + Clean(vwapFastBuffer); + Clean(vwapSlowBuffer); + Clean(xhkSMLowBuffer); + Clean(x3maFastBuffer); + Clean(x3maSlowBuffer); + Clean(downTrendBuffer); + Clean(vwapPriceBuffer); + Clean(xhkRawLowBuffer); + Clean(xhkSMOpenBuffer); + Clean(xhkSMHighBuffer); + Clean(xhkRawOpenBuffer); + Clean(xhkRawHighBuffer); + Clean(xhkSMCloseBuffer); + Clean(vwapVolumeBuffer); + Clean(xhkRawCloseBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(vwapMidStateBuffer); + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(x3maMidStateBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapSlowStateBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + Clean(x3maFastStateBuffer); + Clean(x3maSlowStateBuffer); + + // + ArraySetAsSeries(maBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(upTBuffer, true); + ArraySetAsSeries(adxBuffer, true); + ArraySetAsSeries(adxPBuffer, true); + ArraySetAsSeries(adxMBuffer, true); + ArraySetAsSeries(volumeBuffer, true); + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(downTBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(upTrendBuffer, true); + ArraySetAsSeries(x3maMidBuffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(xhkSMLowBuffer, true); + ArraySetAsSeries(x3maFastBuffer, true); + ArraySetAsSeries(x3maSlowBuffer, true); + ArraySetAsSeries(downTrendBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(xhkRawLowBuffer, true); + ArraySetAsSeries(xhkSMOpenBuffer, true); + ArraySetAsSeries(xhkSMHighBuffer, true); + ArraySetAsSeries(xhkRawOpenBuffer, true); + ArraySetAsSeries(xhkRawHighBuffer, true); + ArraySetAsSeries(xhkSMCloseBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(xhkRawCloseBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(x3maMidStateBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + ArraySetAsSeries(x3maFastStateBuffer, true); + ArraySetAsSeries(x3maSlowStateBuffer, true); + + // + cheMin = 0; + cheMax = 0; + vwapMin = 0; + vwapMax = 0; + x3maMin = 0; + x3maMax = 0; + + // + // Slopes ... + + rsiSlope = 0; + strSlope = 0; + atrUpperSlope = 0; + atrLowerSlope = 0; + vwapFastSlope = 0; + vwapMidSlope = 0; + vwapSlowSlope = 0; + + // + // Conditions ... + + // + isRsiSlopeBullish = false; + isStrSlopeBullish = false; + isAtrUpperSlopeBullish = false; + isAtrLowerSlopeBullish = false; + isVwapFastSlopeBullish = false; + isVwapMidSlopeBullish = false; + isVwapSlowSlopeBullish = false; + + // + isRsiSlopeBearish = false; + isStrSlopeBearish = false; + isAtrUpperSlopeBearish = false; + isAtrLowerSlopeBearish = false; + isVwapFastSlopeBearish = false; + isVwapMidSlopeBearish = false; + isVwapSlowSlopeBearish = false; + + // + // RSI ... + + // + isRsiOverBought = false; + isRsiCrossedOverOverBought = false; + isRsiCrossedUnderOverBought = false; + + // + isRsiOverSold = false; + isRsiCrossedUnderOverSold = false; + isRsiCrossedOverOverSold = false; + + // + // ATR ... + + // + isBreakedUpAtrUpper = false; + isBreakedUpAtrLower = false; + isClosedOverAtrUpper = false; + isClosedOverAtrLower = false; + isRejectedUpAtrUpper = false; + isRejectedUpAtrLower = false; + isClosedUnderAtrUpper = false; + isClosedUnderAtrLower = false; + isBreakedDownAtrUpper = false; + isBreakedDownAtrLower = false; + isRejectedDownAtrUpper = false; + isRejectedDownAtrLower = false; + + // + // DON ... + + // + isRejectedDonOpenUpper = false; + isRejectedDonHighUpper = false; + isRejectedDonLowUpper = false; + isRejectedDonCloseUpper = false; + isRejectedDonOpenLower = false; + isRejectedDonHighLower = false; + isRejectedDonLowLower = false; + isRejectedDonCloseLower = false; + isBreakedDonOpenUpper = false; + isBreakedDonHighUpper = false; + isBreakedDonLowUpper = false; + isBreakedDonCloseUpper = false; + isBreakedDonOpenLower = false; + isBreakedDonHighLower = false; + isBreakedDonLowLower = false; + isBreakedDonCloseLower = false; + + // + // SAR ... + + // + isSarBullish = false; + isSarBearish = false; + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + // PV ... + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + isRejectedPrevPeak = false; + isBreakedUpPrevPeak = false; + + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + isRejectedPrevVale = false; + isBreakedDownPrevVale = false; + + // + // STR ... + + // + isStrBullish = false; + isStrBearish = false; + isStrSwitchedToBullish = false; + isStrSwitchedToBearish = false; + + // + // VWAP ... + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + isVWapFastNeutural = false; + isVWapSlowNeutural = false; + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + isVWapSwitchedToNeuturalState = false; + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + // X3MA ... + isX3MaMidBullish = false; + isX3MaMidBearish = false; + isX3MaFastBullish = false; + isX3MaFastBearish = false; + isX3MaMidNeutural = false; + isX3MaSlowBullish = false; + isX3MaSlowBearish = false; + isX3MaFastOverMid = false; + isX3MaMidOverSlow = false; + isX3MaFastNeutural = false; + isX3MaSlowNeutural = false; + isX3MaFastUnderMid = false; + isX3MaMidUnderSlow = false; + isX3MaBullishState = false; + isX3MaBearishState = false; + isX3MaNeuturalState = false; + isX3MaBullishOrdered = false; + isX3MaBearishOrdered = false; + isX3MaSwitchedToBullishState = false; + isX3MaSwitchedToBearishState = false; + isX3MaSwitchedToNeuturalState = false; + isX3MaSwitchedToBullishOrdered = false; + isX3MaSwitchedToBearishOrdered = false; + + // + // CHE ... + + // + isCheBullish = false; + isCheBearish = false; + isChe1Bullish = false; + isChe1Bearish = false; + isChe2Bullish = false; + isChe2Bearish = false; + isClosedOverCheMin = false; + isClosedOverCheMax = false; + isClosedUnderCheMin = false; + isClosedUnderCheMax = false; + isCheSwitchedToBullish = false; + isCheSwitchedToBearish = false; + isChe1SwitchedToBullish = false; + isChe1SwitchedToBearish = false; + isChe2SwitchedToBullish = false; + isChe2SwitchedToBearish = false; + + // + // XHK ... + isSMHKBullish = false; + isRawHKBullish = false; + isSMHKBearish = false; + isRawHKBearish = false; + isBreakedUpSMHK = false; + isBreakedUpRawHK = false; + isRejectedUpSMHK = false; + isClosedOverSMHK = false; + isRejectedUpRawHK = false; + isBreakedDownSMHK = false; + isClosedUnderSMHK = false; + isClosedOverRawHK = false; + isClosedUnderRawHK = false; + isBreakedDownRawHK = false; + isRejectedDownSMHK = false; + isRejectedDownRawHK = false; + isRawHKBreakedUpSMHK = false; + isRawHKClosedOverSMHK = false; + isSMHKSwitchedToBearish = false; + isRawHKSwitchedToBearish = false; + isRawHKClosedUnderSMHK = false; + isRawHKBreakedDownSMHK = false; + isSMHKSwitchedToBullish = false; + isRawHKSwitchedToBullish = false; + + // + // Complex Conditions ... + + // + isSarIncreased = false; + isSarDecreased = false; + isX3MaFatsOverMid = false; + isSarEqualsToPeak = false; + isSarEqualsToVale = false; + isStrEqualsToPeak = false; + isStrEqualsToVale = false; + isX3MaMinBreakedUp = false; + isX3MaMaxBreakedUp = false; + isX3MaFatsUnderMid = false; + isX3MaFatsOverSlow = false; + isAtrUpperOverPeak = false; + isPeakOverAtrUpper = false; + isStrUpperOverPeak = false; + isStrLowerOverVale = false; + isBreakedUpPrevSar = false; + isBreakedUpPrevStr = false; + isVWapMinBreakedUp = false; + isVWapMaxBreakedUp = false; + isClosedOverCheMin = false; + isClosedOverCheMax = false; + isX3MaFatsUnderSlow = false; + isAtrLowerUnderVale = false; + isClosedOverX3MaMin = false; + isClosedOverX3MaMax = false; + isValeUnderAtrLower = false; + isStrUpperUnderPeak = false; + isStrLowerUnderVale = false; + isClosedUnderCheMin = false; + isClosedUnderCheMax = false; + isClosedOverVWapMin = false; + isClosedOverVWapMax = false; + isX3MaMinBreakedDown = false; + isX3MaMaxBreakedDown = false; + isClosedUnderX3MaMin = false; + isClosedUnderX3MaMax = false; + isBreakedDownPrevSar = false; + isBreakedDownPrevStr = false; + isStrCrossedOverVale = false; + isSarCrossedOverVale = false; + isClosedUnderVWapMin = false; + isClosedUnderVWapMax = false; + isVWapMinBreakedDown = false; + isVWapMaxBreakedDown = false; + isX3MaFatsOverMidPrev = false; + isSarCrossedUnderPeak = false; + isStrCrossedUnderPeak = false; + isNewPeakOverAtrUpper = false; + isBreakedUpPrevCheMin = false; + isBreakedUpPrevCheMax = false; + isBreakedUpPrevCheLE1 = false; + isBreakedUpPrevCheLE2 = false; + isBreakedUpPrevCheSE1 = false; + isBreakedUpPrevCheSE2 = false; + isX3MaFatsUnderMidPrev = false; + isX3MaFatsOverSlowPrev = false; + isAtrUpperEqualsToPeak = false; + isAtrLowerEqualsToVale = false; + isStrUpperOverAtrUpper = false; + isStrLowerOverAtrLower = false; + isNewValeUnderAtrLower = false; + isAtrUpperCrossedUpPeak = false; + isAtrLowerCrossedUpVale = false; + isStrUpperUnderAtrUpper = false; + isStrLowerUnderAtrLower = false; + isX3MaFatsUnderSlowPrev = false; + isBreakedUpPrevAtrUpper = false; + isBreakedUpPrevAtrLower = false; + isBreakedDownPrevCheMin = false; + isBreakedDownPrevCheMax = false; + isBreakedDownPrevCheLE1 = false; + isBreakedDownPrevCheLE2 = false; + isBreakedDownPrevCheSE1 = false; + isBreakedDownPrevCheSE2 = false; + isX3MaFastCrossedOverMid = false; + isRejectedUpPrevAtrUpper = false; + isRejectedUpPrevAtrLower = false; + isVWapFastCrossedOverMid = false; + isX3MaFastCrossedUnderMid = false; + isX3MaFastCrossedOverSlow = false; + isAtrUpperCrossedDownPeak = false; + isAtrLowerCrossedDownVale = false; + isStrLowerOverDonLowLower = false; + isVWapFastCrossedUnderMid = false; + isBreakedDownPrevAtrUpper = false; + isBreakedDownPrevAtrLower = false; + isStrUpperCrossedOverPeak = false; + isStrLowerCrossedOverVale = false; + isDonLowLowerEqualsToVale = false; + isVWapFastCrossedOverSlow = false; + isX3MaFastCrossedUnderSlow = false; + isStrUpperOverDonHighUpper = false; + isStrLowerUnderDonLowLower = false; + isVWapFastCrossedUnderSlow = false; + isStrUpperCrossedUnderPeak = false; + isStrLowerCrossedUnderVale = false; + isDonHighUpperEqualsToPeak = false; + isRejectedDownPrevAtrUpper = false; + isRejectedDownPrevAtrLower = false; + isStrUpperUnderDonHighUpper = false; + isStrUpperCrossedOverAtrUpper = false; + isStrLowerCrossedOverAtrLower = false; + isStrUpperCrossedUnderAtrUpper = false; + isStrLowerCrossedUnderAtrLower = false; + isStrLowerCrossedOverDonLowLower = false; + isStrUpperCrossedOverDonHighUpper = false; + isStrLowerCrossedUnderDonLowLower = false; + isStrUpperCrossedUnderDonHighUpper = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + double score = 1; + double minScore = 0.5; + double highScore = 1.5; + + // + // SLOPES ... + + // + if (isRsiSlopeBullish) + { + bullishScore += minScore; + } + if (isStrSlopeBullish) + { + bullishScore += minScore; + } + if (isAtrUpperSlopeBullish) + { + bullishScore += minScore; + } + if (isAtrLowerSlopeBullish) + { + bullishScore += minScore; + } + if (isVwapFastSlopeBullish) + { + bullishScore += minScore; + } + if (isVwapMidSlopeBullish) + { + bullishScore += minScore; + } + if (isVwapSlowSlopeBullish) + { + bullishScore += minScore; + } + + // + if (isRsiSlopeBearish) + { + bearishScore += minScore; + } + if (isStrSlopeBearish) + { + bearishScore += minScore; + } + if (isAtrUpperSlopeBearish) + { + bearishScore += minScore; + } + if (isAtrLowerSlopeBearish) + { + bearishScore += minScore; + } + if (isVwapFastSlopeBearish) + { + bearishScore += minScore; + } + if (isVwapMidSlopeBearish) + { + bearishScore += minScore; + } + if (isVwapSlowSlopeBearish) + { + bearishScore += minScore; + } + + // + // COMPLEX ... + + // + if (isRsiOverSold) + { + bullishScore += score; + } + if (isRsiCrossedUnderOverSold) + { + bullishScore += highScore; + } + + // + if (isRsiOverBought) + { + bearishScore += score; + } + if (isRsiCrossedOverOverBought) + { + bearishScore += highScore; + } + + // + // XTREND ... + + // + if (isTrendBullish) + { + bullishScore += minScore; + } + if (isTrendSwitchedToBullish) + { + bullishScore += score; + } + + // + if (isTrendBearish) + { + bearishScore += minScore; + } + if (isTrendSwitchedToBearish) + { + bearishScore += score; + } + + // + // XSAR ... + + // + if (isSarBullish) + { + bullishScore += minScore; + } + if (isSarSwitchedToBullish) + { + bullishScore += score; + } + + // + if (isSarBearish) + { + bearishScore += minScore; + } + if (isSarSwitchedToBearish) + { + bearishScore += score; + } + + // + // XSTR ... + + // + if (isStrBullish) + { + bullishScore += minScore; + } + if (isStrSwitchedToBullish) + { + bullishScore += score; + } + + // + if (isStrBearish) + { + bearishScore += minScore; + } + if (isStrSwitchedToBearish) + { + bearishScore += score; + } + + // + // XCHE ... + + // + if (isCheBullish) + { + bullishScore += score; + } + if (isCheSwitchedToBullish) + { + bullishScore += highScore; + } + if (isChe1Bullish && + !isCheBullish && + !isCheSwitchedToBullish) + { + bullishScore += minScore; + } + if (isChe1SwitchedToBullish && + !isCheBullish && + !isCheSwitchedToBullish) + { + bullishScore += minScore; + } + + // + if (isCheBearish) + { + bearishScore += score; + } + if (isCheSwitchedToBearish) + { + bearishScore += highScore; + } + if (isChe1Bearish && + !isCheBearish && + !isCheSwitchedToBearish) + { + bearishScore += minScore; + } + if (isChe1SwitchedToBearish && + !isCheBearish && + !isCheSwitchedToBearish) + { + bearishScore += minScore; + } + + // + // XVWAP ... + + // + if (isVWapBullishState) + { + bullishScore += score; + } + if (isVWapBullishOrdered) + { + bullishScore += score; + } + if (isVWapSwitchedToBullishState) + { + bullishScore += highScore; + } + if (isVWapSwitchedToBullishOrdered) + { + bullishScore += highScore; + } + if (!isVWapBullishState && + !isVWapSwitchedToBullishState) + { + // + if (isVWapFastBullish) + { + bullishScore += minScore; + } + if (isVWapSlowBullish) + { + bullishScore += minScore; + } + } + if (!isVWapBullishOrdered && + !isVWapSwitchedToBullishOrdered) + { + // + if (isVWapFastOverMid) + { + bullishScore += minScore; + } + if (isVWapMidOverSlow) + { + bullishScore += minScore; + } + } + + // + if (isVWapBearishState) + { + bearishScore += score; + } + if (isVWapBearishOrdered) + { + bearishScore += score; + } + if (isVWapSwitchedToBearishState) + { + bearishScore += highScore; + } + if (isVWapSwitchedToBearishOrdered) + { + bearishScore += highScore; + } + if (!isVWapBearishState && + !isVWapSwitchedToBearishState) + { + // + if (isVWapFastBearish) + { + bearishScore += minScore; + } + if (isVWapSlowBearish) + { + bearishScore += minScore; + } + } + if (!isVWapBearishOrdered && + !isVWapSwitchedToBearishOrdered) + { + // + if (isVWapFastUnderMid) + { + bearishScore += minScore; + } + if (isVWapMidUnderSlow) + { + bearishScore += minScore; + } + } + + // + // X3MA ... + + // + if (isX3MaBullishState) + { + bullishScore += score; + } + if (isX3MaBullishOrdered) + { + bullishScore += score; + } + if (isX3MaSwitchedToBullishState) + { + bullishScore += highScore; + } + if (isX3MaSwitchedToBullishOrdered) + { + bullishScore += highScore; + } + if (!isX3MaBullishState && + !isX3MaSwitchedToBullishState) + { + // + if (isX3MaFastBullish) + { + bullishScore += minScore; + } + if (isX3MaSlowBullish) + { + bullishScore += minScore; + } + } + if (!isX3MaBullishOrdered && + !isX3MaSwitchedToBullishOrdered) + { + // + if (isX3MaFastOverMid) + { + bullishScore += minScore; + } + if (isX3MaMidOverSlow) + { + bullishScore += minScore; + } + } + + // + if (isX3MaBearishState) + { + bearishScore += score; + } + if (isX3MaBearishOrdered) + { + bearishScore += score; + } + if (isX3MaSwitchedToBearishState) + { + bearishScore += highScore; + } + if (isX3MaSwitchedToBearishOrdered) + { + bearishScore += highScore; + } + if (!isX3MaBearishState && + !isX3MaSwitchedToBearishState) + { + // + if (isX3MaFastBearish) + { + bearishScore += minScore; + } + if (isX3MaSlowBearish) + { + bearishScore += minScore; + } + } + if (!isX3MaBearishOrdered && + !isX3MaSwitchedToBearishOrdered) + { + // + if (isX3MaFastUnderMid) + { + bearishScore += minScore; + } + if (isX3MaMidUnderSlow) + { + bearishScore += minScore; + } + } + + // + // XSMHK ... + + // + if (isSMHKBullish) + { + bullishScore += minScore; + } + if (isRawHKBullish) + { + bullishScore += minScore; + } + if (isClosedOverSMHK) + { + bullishScore += minScore; + } + if (isClosedOverRawHK) + { + bullishScore += minScore; + } + if (isRawHKClosedOverSMHK) + { + bullishScore += minScore; + } + if (isSMHKSwitchedToBullish) + { + bullishScore += highScore; + } + if (isRawHKSwitchedToBullish) + { + bullishScore += highScore; + } + + // + if (isSMHKBearish) + { + bearishScore += minScore; + } + if (isRawHKBearish) + { + bearishScore += minScore; + } + if (isClosedUnderSMHK) + { + bearishScore += minScore; + } + if (isClosedUnderRawHK) + { + bearishScore += minScore; + } + if (isRawHKClosedUnderSMHK) + { + bearishScore += minScore; + } + if (isSMHKSwitchedToBearish) + { + bearishScore += highScore; + } + if (isRawHKSwitchedToBullish) + { + bearishScore += highScore; + } + + // + // Complex Conditions ... + + // + if (isSarIncreased) + { + bullishScore += minScore; + } + if (isSarEqualsToVale) + { + bullishScore += minScore; + } + if (isBreakedUpPrevSar) + { + bullishScore += minScore; + } + if (isSarCrossedOverVale) + { + bullishScore += score; + } + + // + if (isAtrLowerUnderVale) + { + bullishScore += minScore; + } + if (isValeUnderAtrLower) + { + bullishScore += minScore; + } + if (isNewValeUnderAtrLower) + { + bullishScore += minScore; + } + if (isAtrLowerEqualsToVale) + { + bullishScore += minScore; + } + if (isStrLowerOverAtrLower) + { + bullishScore += minScore; + } + if (isStrUpperOverAtrUpper) + { + bullishScore += minScore; + } + if (isAtrLowerCrossedUpVale) + { + bullishScore += score; + } + if (isAtrUpperCrossedUpPeak) + { + bullishScore += score; + } + if (isBreakedUpPrevAtrLower) + { + bullishScore += minScore; + } + if (isBreakedUpPrevAtrUpper) + { + bullishScore += minScore; + } + if (isRejectedUpPrevAtrUpper) + { + bullishScore += minScore; + } + if (isRejectedUpPrevAtrLower) + { + bullishScore += minScore; + } + if (isStrLowerCrossedOverAtrLower) + { + bullishScore += score; + } + if (isStrUpperCrossedOverAtrUpper) + { + bullishScore += score; + } + + // + if (isBreakedUpPrevStr) + { + bullishScore += minScore; + } + if (isStrEqualsToVale) + { + bullishScore += minScore; + } + if (isStrLowerOverVale) + { + bullishScore += minScore; + } + if (isStrLowerUnderVale) + { + bullishScore += minScore; + } + if (isStrCrossedOverVale) + { + bullishScore += score; + } + if (isStrUpperCrossedOverPeak) + { + bullishScore += score; + } + if (isStrLowerCrossedOverVale) + { + bullishScore += score; + } + if (isStrLowerUnderDonLowLower) + { + bullishScore += minScore; + } + if (isStrLowerCrossedOverDonLowLower) + { + bullishScore += score; + } + if (isStrUpperCrossedOverDonHighUpper) + { + bullishScore += score; + } + + // + if (isVWapMinBreakedUp) + { + bullishScore += minScore; + } + if (isVWapMaxBreakedUp) + { + bullishScore += minScore; + } + if (isClosedOverVWapMin) + { + bullishScore += minScore; + } + if (isClosedOverVWapMax) + { + bullishScore += minScore; + } + if (isVWapFastCrossedOverMid) + { + bullishScore += score; + } + if (isVWapFastCrossedOverSlow) + { + bullishScore += score; + } + + // + if (isX3MaMinBreakedUp) + { + bullishScore += minScore; + } + if (isX3MaMaxBreakedUp) + { + bullishScore += minScore; + } + if (isClosedOverX3MaMin) + { + bullishScore += minScore; + } + if (isClosedOverX3MaMax) + { + bullishScore += minScore; + } + if (isX3MaFastCrossedOverMid) + { + bullishScore += score; + } + if (isX3MaFastCrossedOverSlow) + { + bullishScore += score; + } + + // + if (isClosedOverCheMin) + { + bullishScore += minScore; + } + if (isClosedOverCheMax) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheMin) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheMax) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheLE1) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheLE2) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheSE1) + { + bullishScore += minScore; + } + if (isBreakedUpPrevCheSE2) + { + bullishScore += minScore; + } + if (isDonLowLowerEqualsToVale) + { + bullishScore += minScore; + } + + // + // + // + + // + if (isSarDecreased) + { + bearishScore += minScore; + } + if (isSarEqualsToPeak) + { + bearishScore += minScore; + } + if (isBreakedDownPrevSar) + { + bearishScore += minScore; + } + if (isSarCrossedUnderPeak) + { + bearishScore += score; + } + + // + if (isAtrUpperOverPeak) + { + bearishScore += minScore; + } + if (isPeakOverAtrUpper) + { + bearishScore += minScore; + } + if (isNewPeakOverAtrUpper) + { + bearishScore += minScore; + } + if (isAtrUpperEqualsToPeak) + { + bearishScore += minScore; + } + if (isStrLowerUnderAtrLower) + { + bearishScore += minScore; + } + if (isStrUpperUnderAtrUpper) + { + bearishScore += minScore; + } + if (isAtrLowerCrossedDownVale) + { + bearishScore += score; + } + if (isAtrUpperCrossedDownPeak) + { + bearishScore += score; + } + if (isBreakedDownPrevAtrUpper) + { + bearishScore += minScore; + } + if (isBreakedDownPrevAtrLower) + { + bearishScore += minScore; + } + if (isRejectedDownPrevAtrUpper) + { + bearishScore += minScore; + } + if (isRejectedDownPrevAtrLower) + { + bearishScore += minScore; + } + if (isStrLowerCrossedUnderAtrLower) + { + bearishScore += score; + } + if (isStrUpperCrossedUnderAtrUpper) + { + bearishScore += score; + } + + // + if (isStrEqualsToPeak) + { + bearishScore += minScore; + } + if (isStrUpperOverPeak) + { + bearishScore += minScore; + } + if (isStrUpperUnderPeak) + { + bearishScore += minScore; + } + if (isBreakedDownPrevStr) + { + bearishScore += minScore; + } + if (isStrCrossedUnderPeak) + { + bearishScore += score; + } + if (isStrLowerOverDonLowLower) + { + bearishScore += minScore; + } + if (isStrUpperOverDonHighUpper) + { + bearishScore += minScore; + } + if (isStrUpperCrossedUnderPeak) + { + bearishScore += score; + } + if (isStrLowerCrossedUnderVale) + { + bearishScore += score; + } + if (isStrUpperUnderDonHighUpper) + { + bearishScore += minScore; + } + if (isStrLowerCrossedUnderDonLowLower) + { + bearishScore += score; + } + if (isStrUpperCrossedUnderDonHighUpper) + { + bearishScore += score; + } + + // + if (isClosedUnderVWapMin) + { + bearishScore += minScore; + } + if (isClosedUnderVWapMax) + { + bearishScore += minScore; + } + if (isVWapMinBreakedDown) + { + bearishScore += minScore; + } + if (isVWapMaxBreakedDown) + { + bearishScore += minScore; + } + if (isVWapFastCrossedUnderMid) + { + bearishScore += score; + } + if (isVWapFastCrossedUnderSlow) + { + bearishScore += score; + } + + // + if (isX3MaMinBreakedDown) + { + bearishScore += minScore; + } + if (isX3MaMaxBreakedDown) + { + bearishScore += minScore; + } + if (isClosedUnderX3MaMin) + { + bearishScore += minScore; + } + if (isClosedUnderX3MaMax) + { + bearishScore += minScore; + } + if (isX3MaFastCrossedUnderMid) + { + bearishScore += score; + } + if (isX3MaFastCrossedUnderSlow) + { + bearishScore += score; + } + + // + if (isClosedUnderCheMin) + { + bearishScore += minScore; + } + if (isClosedUnderCheMax) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheMin) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheMax) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheLE1) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheLE2) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheSE1) + { + bearishScore += minScore; + } + if (isBreakedDownPrevCheSE2) + { + bearishScore += minScore; + } + if (isDonHighUpperEqualsToPeak) + { + bearishScore += minScore; + } + + // + // + // + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + "-----------------------" + separator + + "SAR ..." + separator + + "-----------------------" + separator + + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "Trend ..." + separator + + "-----------------------" + separator + + ToString("isTrendBullish", isTrendBullish, ignoreFalseConditions, separator) + + ToString("isTrendBearish", isTrendBearish, ignoreFalseConditions, separator) + + ToString("isTrendSwitchedToBullish", isTrendSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isTrendSwitchedToBearish", isTrendSwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "STR ..." + separator + + "-----------------------" + separator + + ToString("isStrBullish", isStrBullish, ignoreFalseConditions, separator) + + ToString("isStrBearish", isStrBearish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBullish", isStrSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBearish", isStrSwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "PV ..." + separator + + "-----------------------" + separator + + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevPeak", isRejectedPrevPeak, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevPeak", isBreakedUpPrevPeak, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevVale", isRejectedPrevVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevVale", isBreakedDownPrevVale, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "> RSI ..." + separator + + "-----------------------" + separator + + ToString("isRsiOverBought", isRsiOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverBought", isRsiCrossedOverOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverBought", isRsiCrossedUnderOverBought, ignoreFalseConditions, separator) + + ToString("isRsiOverSold", isRsiOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverSold", isRsiCrossedUnderOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverSold", isRsiCrossedOverOverSold, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "ATR ..." + separator + + "-----------------------" + separator + + ToString("isClosedOverAtrUpper", isClosedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedOverAtrLower", isClosedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrUpper", isClosedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrLower", isClosedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrUpper", isRejectedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrUpper", isRejectedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrLower", isRejectedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrLower", isRejectedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrUpper", isBreakedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrUpper", isBreakedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrLower", isBreakedUpAtrLower, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "DON ..." + separator + + "-----------------------" + separator + + ToString("isBreakedDownAtrLower", isBreakedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonOpenUpper", isRejectedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighUpper", isRejectedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowUpper", isRejectedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseUpper", isRejectedDonCloseUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonOpenLower", isRejectedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighLower", isRejectedDonHighLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowLower", isRejectedDonLowLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseLower", isRejectedDonCloseLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonOpenUpper", isBreakedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighUpper", isBreakedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowUpper", isBreakedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseUpper", isBreakedDonCloseUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonOpenLower", isBreakedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighLower", isBreakedDonHighLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowLower", isBreakedDonLowLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseLower", isBreakedDonCloseLower, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "VWAP ..." + separator + + "-----------------------" + separator + + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "X3MA ..." + separator + + "-----------------------" + separator + + ToString("isX3MaMidBullish", isX3MaMidBullish, ignoreFalseConditions, separator) + + ToString("isX3MaMidBearish", isX3MaMidBearish, ignoreFalseConditions, separator) + + ToString("isX3MaFastBullish", isX3MaFastBullish, ignoreFalseConditions, separator) + + ToString("isX3MaFastBearish", isX3MaFastBearish, ignoreFalseConditions, separator) + + ToString("isX3MaMidNeutural", isX3MaMidNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaSlowBullish", isX3MaSlowBullish, ignoreFalseConditions, separator) + + ToString("isX3MaSlowBearish", isX3MaSlowBearish, ignoreFalseConditions, separator) + + ToString("isX3MaFastOverMid", isX3MaFastOverMid, ignoreFalseConditions, separator) + + ToString("isX3MaMidOverSlow", isX3MaMidOverSlow, ignoreFalseConditions, separator) + + ToString("isX3MaFastNeutural", isX3MaFastNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaSlowNeutural", isX3MaSlowNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaFastUnderMid", isX3MaFastUnderMid, ignoreFalseConditions, separator) + + ToString("isX3MaMidUnderSlow", isX3MaMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isX3MaBullishState", isX3MaBullishState, ignoreFalseConditions, separator) + + ToString("isX3MaBearishState", isX3MaBearishState, ignoreFalseConditions, separator) + + ToString("isX3MaNeuturalState", isX3MaNeuturalState, ignoreFalseConditions, separator) + + ToString("isX3MaBullishOrdered", isX3MaBullishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaBearishOrdered", isX3MaBearishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBullishState", isX3MaSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBearishState", isX3MaSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToNeuturalState", isX3MaSwitchedToNeuturalState, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBullishOrdered", isX3MaSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBearishOrdered", isX3MaSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "CHE ..." + separator + + "-----------------------" + separator + + ToString("isChe1Bullish", isChe1Bullish, ignoreFalseConditions, separator) + + ToString("isChe1Bearish", isChe1Bearish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBullish", isChe1SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBearish", isChe1SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isChe2Bullish", isChe2Bullish, ignoreFalseConditions, separator) + + ToString("isChe2Bearish", isChe2Bearish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBullish", isChe2SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBearish", isChe2SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isCheBullish", isCheBullish, ignoreFalseConditions, separator) + + ToString("isCheBearish", isCheBearish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBullish", isCheSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBearish", isCheSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMin", isClosedOverCheMin, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMax", isClosedOverCheMax, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMin", isClosedUnderCheMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMax", isClosedUnderCheMax, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "HK ..." + separator + + "-----------------------" + separator + + ToString("isSMHKBullish", isSMHKBullish, ignoreFalseConditions, separator) + + ToString("isRawHKBullish", isRawHKBullish, ignoreFalseConditions, separator) + + ToString("isSMHKBearish", isSMHKBearish, ignoreFalseConditions, separator) + + ToString("isRawHKBearish", isRawHKBearish, ignoreFalseConditions, separator) + + ToString("isBreakedUpSMHK", isBreakedUpSMHK, ignoreFalseConditions, separator) + + ToString("isBreakedUpRawHK", isBreakedUpRawHK, ignoreFalseConditions, separator) + + ToString("isRejectedUpSMHK", isRejectedUpSMHK, ignoreFalseConditions, separator) + + ToString("isClosedOverSMHK", isClosedOverSMHK, ignoreFalseConditions, separator) + + ToString("isRejectedUpRawHK", isRejectedUpRawHK, ignoreFalseConditions, separator) + + ToString("isBreakedDownSMHK", isBreakedDownSMHK, ignoreFalseConditions, separator) + + ToString("isClosedUnderSMHK", isClosedUnderSMHK, ignoreFalseConditions, separator) + + ToString("isClosedOverRawHK", isClosedOverRawHK, ignoreFalseConditions, separator) + + ToString("isClosedUnderRawHK", isClosedUnderRawHK, ignoreFalseConditions, separator) + + ToString("isBreakedDownRawHK", isBreakedDownRawHK, ignoreFalseConditions, separator) + + ToString("isRejectedDownSMHK", isRejectedDownSMHK, ignoreFalseConditions, separator) + + ToString("isRejectedDownRawHK", isRejectedDownRawHK, ignoreFalseConditions, separator) + + ToString("isRawHKBreakedUpSMHK", isRawHKBreakedUpSMHK, ignoreFalseConditions, separator) + + ToString("isRawHKClosedOverSMHK", isRawHKClosedOverSMHK, ignoreFalseConditions, separator) + + ToString("isSMHKSwitchedToBearish", isSMHKSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isRawHKSwitchedToBearish", isRawHKSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isRawHKClosedUnderSMHK", isRawHKClosedUnderSMHK, ignoreFalseConditions, separator) + + ToString("isRawHKBreakedDownSMHK", isRawHKBreakedDownSMHK, ignoreFalseConditions, separator) + + ToString("isSMHKSwitchedToBullish", isSMHKSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isRawHKSwitchedToBullish", isRawHKSwitchedToBullish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "Slopes ..." + separator + + "-----------------------" + separator + + ToString("isRsiSlopeBullish", isRsiSlopeBullish, ignoreFalseConditions, separator) + + ToString("isStrSlopeBullish", isStrSlopeBullish, ignoreFalseConditions, separator) + + ToString("isAtrUpperSlopeBullish", isAtrUpperSlopeBullish, ignoreFalseConditions, separator) + + ToString("isAtrLowerSlopeBullish", isAtrLowerSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapFastSlopeBullish", isVwapFastSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapMidSlopeBullish", isVwapMidSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapSlowSlopeBullish", isVwapSlowSlopeBullish, ignoreFalseConditions, separator) + + ToString("isRsiSlopeBearish", isRsiSlopeBearish, ignoreFalseConditions, separator) + + ToString("isStrSlopeBearish", isStrSlopeBearish, ignoreFalseConditions, separator) + + ToString("isAtrUpperSlopeBearish", isAtrUpperSlopeBearish, ignoreFalseConditions, separator) + + ToString("isAtrLowerSlopeBearish", isAtrLowerSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapFastSlopeBearish", isVwapFastSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapMidSlopeBearish", isVwapMidSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapSlowSlopeBearish", isVwapSlowSlopeBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "Coplex ..." + separator + + "-----------------------" + separator + + ToString("isSarIncreased", isSarIncreased, ignoreFalseConditions, separator) + + ToString("isSarDecreased", isSarDecreased, ignoreFalseConditions, separator) + + ToString("isSarEqualsToPeak", isSarEqualsToPeak, ignoreFalseConditions, separator) + + + ToString("isStrEqualsToPeak", isStrEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isStrEqualsToVale", isStrEqualsToVale, ignoreFalseConditions, separator) + + ToString("isPeakOverAtrUpper", isPeakOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevSar", isBreakedUpPrevSar, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevStr", isBreakedUpPrevStr, ignoreFalseConditions, separator) + + ToString("isVWapMinBreakedUp", isVWapMinBreakedUp, ignoreFalseConditions, separator) + + ToString("isVWapMaxBreakedUp", isVWapMaxBreakedUp, ignoreFalseConditions, separator) + + ToString("isStrUpperOverPeak", isStrUpperOverPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerOverVale", isStrLowerOverVale, ignoreFalseConditions, separator) + + ToString("isAtrUpperOverPeak", isAtrUpperOverPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerUnderVale", isAtrLowerUnderVale, ignoreFalseConditions, separator) + + ToString("isClosedOverVWapMin", isClosedOverVWapMin, ignoreFalseConditions, separator) + + ToString("isClosedOverVWapMax", isClosedOverVWapMax, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderPeak", isStrUpperUnderPeak, ignoreFalseConditions, separator) + + ToString("isValeUnderAtrLower", isValeUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderVale", isStrLowerUnderVale, ignoreFalseConditions, separator) + + ToString("isVWapMinBreakedDown", isVWapMinBreakedDown, ignoreFalseConditions, separator) + + ToString("isVWapMaxBreakedDown", isVWapMaxBreakedDown, ignoreFalseConditions, separator) + + ToString("isClosedUnderVWapMin", isClosedUnderVWapMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderVWapMax", isClosedUnderVWapMax, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevSar", isBreakedDownPrevSar, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevStr", isBreakedDownPrevStr, ignoreFalseConditions, separator) + + ToString("isSarCrossedOverVale", isSarCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isStrCrossedOverVale", isStrCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheLE1", isBreakedUpPrevCheLE1, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheLE2", isBreakedUpPrevCheLE2, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheSE1", isBreakedUpPrevCheSE1, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheSE2", isBreakedUpPrevCheSE2, ignoreFalseConditions, separator) + + ToString("isSarCrossedUnderPeak", isSarCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isStrCrossedUnderPeak", isStrCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverAtrUpper", isNewPeakOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheMin", isBreakedUpPrevCheMin, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheMax", isBreakedUpPrevCheMax, ignoreFalseConditions, separator) + + ToString("isNewValeUnderAtrLower", isNewValeUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrUpperOverAtrUpper", isStrUpperOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerOverAtrLower", isStrLowerOverAtrLower, ignoreFalseConditions, separator) + + ToString("isAtrUpperEqualsToPeak", isAtrUpperEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerEqualsToVale", isAtrLowerEqualsToVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheMin", isBreakedDownPrevCheMin, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheMax", isBreakedDownPrevCheMax, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheLE1", isBreakedDownPrevCheLE1, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheLE2", isBreakedDownPrevCheLE2, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheSE1", isBreakedDownPrevCheSE1, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheSE2", isBreakedDownPrevCheSE2, ignoreFalseConditions, separator) + + ToString("isAtrUpperCrossedUpPeak", isAtrUpperCrossedUpPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerCrossedUpVale", isAtrLowerCrossedUpVale, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderAtrUpper", isStrUpperUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderAtrLower", isStrLowerUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevAtrUpper", isBreakedUpPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevAtrLower", isBreakedUpPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedOverMid", isVWapFastCrossedOverMid, ignoreFalseConditions, separator) + + ToString("isRejectedUpPrevAtrUpper", isRejectedUpPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpPrevAtrLower", isRejectedUpPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isAtrUpperCrossedDownPeak", isAtrUpperCrossedDownPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerCrossedDownVale", isAtrLowerCrossedDownVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevAtrUpper", isBreakedDownPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevAtrLower", isBreakedDownPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedUnderMid", isVWapFastCrossedUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedOverSlow", isVWapFastCrossedOverSlow, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverPeak", isStrUpperCrossedOverPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerOverDonLowLower", isStrLowerOverDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverVale", isStrLowerCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isDonLowLowerEqualsToVale", isDonLowLowerEqualsToVale, ignoreFalseConditions, separator) + + ToString("isRejectedDownPrevAtrUpper", isRejectedDownPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownPrevAtrLower", isRejectedDownPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedUnderSlow", isVWapFastCrossedUnderSlow, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderPeak", isStrUpperCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderVale", isStrLowerCrossedUnderVale, ignoreFalseConditions, separator) + + ToString("isDonHighUpperEqualsToPeak", isDonHighUpperEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isStrUpperOverDonHighUpper", isStrUpperOverDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderDonLowLower", isStrLowerUnderDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderDonHighUpper", isStrUpperUnderDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverAtrUpper", isStrUpperCrossedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverAtrLower", isStrLowerCrossedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderAtrUpper", isStrUpperCrossedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderAtrLower", isStrLowerCrossedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverDonLowLower", isStrLowerCrossedOverDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverDonHighUpper", isStrUpperCrossedOverDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderDonLowLower", isStrLowerCrossedUnderDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderDonHighUpper", isStrUpperCrossedUnderDonHighUpper, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Implementation ... +class XCX121Helper : public XCBase +{ + // + public: + // + + // + // Helpers ... + XCX121XPVHelper *xpvHelper; + XCX121XHKHelper *xhkHelper; + XCX121XATRHelper *xatrHelper; + XCX121XSTRHelper *xstrHelper; + XCX121XCHEHelper *xcheHelper; + XCX121XDONHelper *xdonHelper; + XCX121X3MAHelper *x3maHelper; + XCX121XVWAPHelper *xvwapHelper; + XCX121XTRENDHelper *xtrendHelper; + + // + // Constructors ... + XCX121Helper() + { + } + + // + // Deconstructor ... + ~XCX121Helper() + { + // + mInputs.Clean(); + xpvInputs.Clean(); + xhkInputs.Clean(); + xatrInputs.Clean(); + xdonInputs.Clean(); + xstrInputs.Clean(); + xcheInputs.Clean(); + x3maInputs.Clean(); + xvwapInputs.Clean(); + xtrendInputs.Clean(); + + // + delete xpvHelper; + delete xhkHelper; + delete xatrHelper; + delete xstrHelper; + delete xcheHelper; + delete xdonHelper; + delete x3maHelper; + delete xvwapHelper; + delete xtrendHelper; + + // + ZeroMemory(xpvHelper); + ZeroMemory(xhkHelper); + ZeroMemory(xatrHelper); + ZeroMemory(xstrHelper); + ZeroMemory(xcheHelper); + ZeroMemory(xdonHelper); + ZeroMemory(x3maHelper); + ZeroMemory(xvwapHelper); + ZeroMemory(xtrendHelper); + } + + // + string GetSymbol() + { + return mSymbol; + } + + // + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Tools ... + + /** + * Initialize Indicator Helper ... + * + * @param symbol: String, Symbol ... + * @param period: ENUM_TIMEFRAMES member, Period ... + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121Inputs &inputs // Inputs + ) + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + inputs.IsValid(); + if (!result) + { + return result; + } + + // + mSymbol = symbol; + mPeriod = period; + + // + // Setting Inputs ... + + // + mInputs = inputs; + xpvInputs = inputs.xpvInputs; + xhkInputs = inputs.xhkInputs; + xatrInputs = inputs.xatrInputs; + xstrInputs = inputs.xstrInputs; + xcheInputs = inputs.xcheInputs; + xdonInputs = inputs.xdonInputs; + x3maInputs = inputs.x3maInputs; + xvwapInputs = inputs.xvwapInputs; + xtrendInputs = inputs.xtrendInputs; + + // + // Initial Helpers ... + + // + // XPV ... + xpvHelper = new XCX121XPVHelper(); + result = xpvHelper.Init( + symbol, + period, + xpvInputs // + ); + if (!result) + { + return result; + } + + // + // XHK ... + xhkHelper = new XCX121XHKHelper(); + result = xhkHelper.Init( + symbol, + period, + xhkInputs // + ); + if (!result) + { + return result; + } + + // + // XATR ... + xatrHelper = new XCX121XATRHelper(); + result = xatrHelper.Init( + symbol, + period, + xatrInputs // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + xstrHelper = new XCX121XSTRHelper(); + result = xstrHelper.Init( + symbol, + period, + xstrInputs // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + xcheHelper = new XCX121XCHEHelper(); + result = xcheHelper.Init( + symbol, + period, + xcheInputs // + ); + if (!result) + { + return result; + } + + // + // XDON ... + xdonHelper = new XCX121XDONHelper(); + result = xdonHelper.Init( + symbol, + period, + xdonInputs // + ); + if (!result) + { + return result; + } + + // + // X3MA ... + x3maHelper = new XCX121X3MAHelper(); + result = x3maHelper.Init( + symbol, + period, + x3maInputs // + ); + if (!result) + { + return result; + } + + // + // XVWAP ... + xvwapHelper = new XCX121XVWAPHelper(); + result = xvwapHelper.Init( + symbol, + period, + xvwapInputs // + ); + if (!result) + { + return result; + } + + // + // XTREND ... + xtrendHelper = new XCX121XTRENDHelper(); + result = xtrendHelper.Init( + symbol, + period, + xtrendInputs // + ); + if (!result) + { + return result; + } + + // + if (inputs.showRSI) + { + // + mRSIHandler = iRSI( + symbol, + period, + xatrInputs.rsiLength, + xatrInputs.rsiAppliedTo // + ); + + // + result = mRSIHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Conditions Readers ... + + // + // XPV ... + bool GetPVConditions( + X121XPVConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xpvHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XHK ... + bool GetHKConditions( + X121XHKConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xhkHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XATR ... + bool GetATRConditions( + X121XATRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xatrHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XSTR ... + bool GetSTRConditions( + X121XSTRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xstrHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XCHE ... + bool GetCHEConditions( + X121XCHEConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xcheHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XDON ... + bool GetDONConditions( + X121XDONConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xdonHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // X3MA ... + bool Get3MAConditions( + X121X3MAConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = x3maHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XVWAP ... + bool GetVWAPConditions( + X121XVWAPConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xvwapHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XTREND ... + bool GetTrendConditions( + X121XTRENDConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xtrendHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + void Free() + { + // + xpvHelper.Free(); + xhkHelper.Free(); + xatrHelper.Free(); + xstrHelper.Free(); + xcheHelper.Free(); + xdonHelper.Free(); + xvwapHelper.Free(); + xtrendHelper.Free(); + } + + // + bool GetConditions( + X121Conditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // XPV ... + X121XPVConditions xpvConditions; + result = GetPVConditions( + xpvConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XHK ... + X121XHKConditions xhkConditions; + result = GetHKConditions( + xhkConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XATR ... + X121XATRConditions xatrConditions; + result = GetATRConditions( + xatrConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + X121XSTRConditions xstrConditions; + result = GetSTRConditions( + xstrConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + X121XCHEConditions xcheConditions; + result = GetCHEConditions( + xcheConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XDON ... + X121XDONConditions xdonConditions; + result = GetDONConditions( + xdonConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // X3MA ... + X121X3MAConditions x3maConditions; + result = Get3MAConditions( + x3maConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XVWAP ... + X121XVWAPConditions xvwapConditions; + result = GetVWAPConditions( + xvwapConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XTREND ... + X121XTRENDConditions xtrendConditions; + result = GetTrendConditions( + xtrendConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Fill Volume Buffer ... + for (int i = barIndex; i < barIndex + loopback; i++) + { + // + // Reading Bar Valuem ... + long iVol = iVolume( + mSymbol, + mPeriod, + i // + ); + + // + Add( + iVol, + conditions.volumeBuffer // + ); + } + + // + // Fill X121 Conditions Reference by Using + // Retrieved Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // XPV ... + + // + // Buffers ... + + // + Copy( + xpvConditions.peaksBuffer, + conditions.peaksBuffer // + ); + + // + Copy( + xpvConditions.valesBuffer, + conditions.valesBuffer // + ); + + // + Copy( + xpvConditions.sarBuffer, + conditions.sarBuffer // + ); + + // + Copy( + xpvConditions.cHHBuffer, + conditions.cHHBuffer // + ); + + // + Copy( + xpvConditions.cLLBuffer, + conditions.cLLBuffer // + ); + + // + Copy( + xpvConditions.sHHBuffer, + conditions.sHHBuffer // + ); + + // + Copy( + xpvConditions.sLLBuffer, + conditions.sLLBuffer // + ); + + // + Copy( + xpvConditions.mHHBuffer, + conditions.mHHBuffer // + ); + + // + Copy( + xpvConditions.mLLBuffer, + conditions.mLLBuffer // + ); + + // + Copy( + xpvConditions.lHHBuffer, + conditions.lHHBuffer // + ); + + // + Copy( + xpvConditions.lLLBuffer, + conditions.lLLBuffer // + ); + + // + Copy( + xpvConditions.hHHBuffer, + conditions.hHHBuffer // + ); + + // + Copy( + xpvConditions.hLLBuffer, + conditions.hLLBuffer // + ); + + // + // Conditions ... + + // + conditions.isNewPeak = xpvConditions.isNewPeak; + conditions.isNewVale = xpvConditions.isNewVale; + conditions.isSarBullish = xpvConditions.isSarBullish; + conditions.isSarBearish = xpvConditions.isSarBearish; + conditions.isNewPeakOverLast = xpvConditions.isNewPeakOverLast; + conditions.isNewValeOverLast = xpvConditions.isNewValeOverLast; + conditions.isNewPeakUnderLast = xpvConditions.isNewPeakUnderLast; + conditions.isNewValeUnderLast = xpvConditions.isNewValeUnderLast; + conditions.isRejectedPrevVale = xpvConditions.isRejectedPrevVale; + conditions.isRejectedPrevPeak = xpvConditions.isRejectedPrevPeak; + conditions.isBreakedUpPrevPeak = xpvConditions.isBreakedUpPrevPeak; + conditions.isBreakedDownPrevVale = xpvConditions.isBreakedDownPrevVale; + conditions.isSarSwitchedToBullish = xpvConditions.isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = xpvConditions.isSarSwitchedToBearish; + + // + // XHK ... + + // + // Buffers ... + + // + Copy( + xhkConditions.xhkRawOpenBuffer, + conditions.xhkRawOpenBuffer // + ); + + // + Copy( + xhkConditions.xhkRawHighBuffer, + conditions.xhkRawHighBuffer // + ); + + // + Copy( + xhkConditions.xhkRawLowBuffer, + conditions.xhkRawLowBuffer // + ); + + // + Copy( + xhkConditions.xhkRawCloseBuffer, + conditions.xhkRawCloseBuffer // + ); + + // + Copy( + xhkConditions.xhkSMOpenBuffer, + conditions.xhkSMOpenBuffer // + ); + + // + Copy( + xhkConditions.xhkSMHighBuffer, + conditions.xhkSMHighBuffer // + ); + + // + Copy( + xhkConditions.xhkSMLowBuffer, + conditions.xhkSMLowBuffer // + ); + + // + Copy( + xhkConditions.xhkSMCloseBuffer, + conditions.xhkSMCloseBuffer // + ); + + // + // Conditions ... + conditions.isSMHKBullish = xhkConditions.isSMHKBullish; + conditions.isRawHKBullish = xhkConditions.isRawHKBullish; + conditions.isSMHKBearish = xhkConditions.isSMHKBearish; + conditions.isRawHKBearish = xhkConditions.isRawHKBearish; + conditions.isBreakedUpSMHK = xhkConditions.isBreakedUpSMHK; + conditions.isBreakedUpRawHK = xhkConditions.isBreakedUpRawHK; + conditions.isRejectedUpSMHK = xhkConditions.isRejectedUpSMHK; + conditions.isClosedOverSMHK = xhkConditions.isClosedOverSMHK; + conditions.isRejectedUpRawHK = xhkConditions.isRejectedUpRawHK; + conditions.isBreakedDownSMHK = xhkConditions.isBreakedDownSMHK; + conditions.isClosedUnderSMHK = xhkConditions.isClosedUnderSMHK; + conditions.isClosedOverRawHK = xhkConditions.isClosedOverRawHK; + conditions.isClosedUnderRawHK = xhkConditions.isClosedUnderRawHK; + conditions.isBreakedDownRawHK = xhkConditions.isBreakedDownRawHK; + conditions.isRejectedDownSMHK = xhkConditions.isRejectedDownSMHK; + conditions.isRejectedDownRawHK = xhkConditions.isRejectedDownRawHK; + conditions.isRawHKBreakedUpSMHK = xhkConditions.isRawHKBreakedUpSMHK; + conditions.isRawHKClosedOverSMHK = xhkConditions.isRawHKClosedOverSMHK; + conditions.isSMHKSwitchedToBearish = xhkConditions.isSMHKSwitchedToBearish; + conditions.isRawHKSwitchedToBearish = xhkConditions.isRawHKSwitchedToBearish; + conditions.isRawHKClosedUnderSMHK = xhkConditions.isRawHKClosedUnderSMHK; + conditions.isRawHKBreakedDownSMHK = xhkConditions.isRawHKBreakedDownSMHK; + conditions.isSMHKSwitchedToBullish = xhkConditions.isSMHKSwitchedToBullish; + conditions.isRawHKSwitchedToBullish = xhkConditions.isRawHKSwitchedToBullish; + + // + // XTREND ... + + // + // Buffers ... + + // + Copy( + xtrendConditions.upTrendBuffer, + conditions.upTrendBuffer // + ); + + // + Copy( + xtrendConditions.downTrendBuffer, + conditions.downTrendBuffer // + ); + + // + Copy( + xtrendConditions.maBuffer, + conditions.maBuffer // + ); + + // + Copy( + xtrendConditions.adxBuffer, + conditions.adxBuffer // + ); + + // + Copy( + xtrendConditions.adxPBuffer, + conditions.adxPBuffer // + ); + + // + Copy( + xtrendConditions.adxMBuffer, + conditions.adxMBuffer // + ); + + // + Copy( + xtrendConditions.upTBuffer, + conditions.upTBuffer // + ); + + // + Copy( + xtrendConditions.downTBuffer, + conditions.downTBuffer // + ); + + // + conditions.isTrendBullish = xtrendConditions.isTrendBullish; + conditions.isTrendBearish = xtrendConditions.isTrendBearish; + conditions.isTrendSwitchedToBullish = xtrendConditions.isTrendSwitchedToBullish; + conditions.isTrendSwitchedToBearish = xtrendConditions.isTrendSwitchedToBearish; + + // + // XATR ... + + // + // Buffers ... + + // + Copy( + xatrConditions.atrUpperBuffer, + conditions.atrUpperBuffer // + ); + + // + Copy( + xatrConditions.atrLowerBuffer, + conditions.atrLowerBuffer // + ); + + // + Copy( + xatrConditions.atrUpperRawBuffer, + conditions.atrUpperRawBuffer // + ); + + // + Copy( + xatrConditions.atrLowerRawBuffer, + conditions.atrLowerRawBuffer // + ); + + // + Copy( + xatrConditions.atrBuffer, + conditions.atrBuffer // + ); + + // + Copy( + xatrConditions.rsiBuffer, + conditions.rsiBuffer // + ); + + // + // Conditions ... + + // + conditions.isRsiOverSold = xatrConditions.isRsiOverSold; + conditions.isRsiOverBought = xatrConditions.isRsiOverBought; + conditions.isBreakedUpAtrUpper = xatrConditions.isBreakedUpAtrUpper; + conditions.isBreakedUpAtrLower = xatrConditions.isBreakedUpAtrLower; + conditions.isClosedOverAtrUpper = xatrConditions.isClosedOverAtrUpper; + conditions.isRejectedUpAtrUpper = xatrConditions.isRejectedUpAtrUpper; + conditions.isRejectedUpAtrLower = xatrConditions.isRejectedUpAtrLower; + conditions.isClosedOverAtrLower = xatrConditions.isClosedOverAtrLower; + conditions.isBreakedDownAtrUpper = xatrConditions.isBreakedDownAtrUpper; + conditions.isBreakedDownAtrLower = xatrConditions.isBreakedDownAtrLower; + conditions.isClosedUnderAtrUpper = xatrConditions.isClosedUnderAtrUpper; + conditions.isClosedUnderAtrLower = xatrConditions.isClosedUnderAtrLower; + conditions.isRejectedDownAtrUpper = xatrConditions.isRejectedDownAtrUpper; + conditions.isRejectedDownAtrLower = xatrConditions.isRejectedDownAtrLower; + conditions.isRsiCrossedOverOverSold = xatrConditions.isRsiCrossedOverOverSold; + conditions.isRsiCrossedUnderOverSold = xatrConditions.isRsiCrossedUnderOverSold; + conditions.isRsiCrossedOverOverBought = xatrConditions.isRsiCrossedOverOverBought; + conditions.isRsiCrossedUnderOverBought = xatrConditions.isRsiCrossedUnderOverBought; + + // + // XSTR ... + + // + // Buffers ... + + // + Copy( + xstrConditions.strBuffer, + conditions.strBuffer // + ); + + // + Copy( + xstrConditions.strPriceBuffer, + conditions.strPriceBuffer // + ); + + // + Copy( + xstrConditions.strUpBuffer, + conditions.strUpBuffer // + ); + + // + Copy( + xstrConditions.strDownBuffer, + conditions.strDownBuffer // + ); + + // + Copy( + xstrConditions.strStateBuffer, + conditions.strStateBuffer // + ); + + // + // Conditions ... + + // + conditions.isStrBullish = xstrConditions.isStrBullish; + conditions.isStrBearish = xstrConditions.isStrBearish; + conditions.isStrSwitchedToBullish = xstrConditions.isStrSwitchedToBullish; + conditions.isStrSwitchedToBearish = xstrConditions.isStrSwitchedToBearish; + + // + // XCHE ... + + // + // Buffers ... + + // + Copy( + xcheConditions.le1Buffer, + conditions.le1Buffer // + ); + + // + Copy( + xcheConditions.se1Buffer, + conditions.se1Buffer // + ); + + // + Copy( + xcheConditions.le2Buffer, + conditions.le2Buffer // + ); + + // + Copy( + xcheConditions.se2Buffer, + conditions.se2Buffer // + ); + + // + Copy( + xcheConditions.le1StartBuffer, + conditions.le1StartBuffer // + ); + + // + Copy( + xcheConditions.se1StartBuffer, + conditions.se1StartBuffer // + ); + + // + Copy( + xcheConditions.le2StartBuffer, + conditions.le2StartBuffer // + ); + + // + Copy( + xcheConditions.se2StartBuffer, + conditions.se2StartBuffer // + ); + + // + // Conditions ... + + conditions.isCheBullish = xcheConditions.isCheBullish; + conditions.isCheBearish = xcheConditions.isCheBearish; + conditions.isChe1Bullish = xcheConditions.isChe1Bullish; + conditions.isChe1Bearish = xcheConditions.isChe1Bearish; + conditions.isChe2Bullish = xcheConditions.isChe2Bullish; + conditions.isChe2Bearish = xcheConditions.isChe2Bearish; + conditions.isClosedOverCheMin = xcheConditions.isClosedOverCheMin; + conditions.isClosedOverCheMax = xcheConditions.isClosedOverCheMax; + conditions.isClosedUnderCheMin = xcheConditions.isClosedUnderCheMin; + conditions.isClosedUnderCheMax = xcheConditions.isClosedUnderCheMax; + conditions.isCheSwitchedToBullish = xcheConditions.isCheSwitchedToBullish; + conditions.isCheSwitchedToBearish = xcheConditions.isCheSwitchedToBearish; + conditions.isChe1SwitchedToBullish = xcheConditions.isChe1SwitchedToBullish; + conditions.isChe1SwitchedToBearish = xcheConditions.isChe1SwitchedToBearish; + conditions.isChe2SwitchedToBullish = xcheConditions.isChe2SwitchedToBullish; + conditions.isChe2SwitchedToBearish = xcheConditions.isChe2SwitchedToBearish; + + // + // XDON ... + + // + // Buffers ... + + // + Copy( + xdonConditions.donOpenUpperBuffer, + conditions.donOpenUpperBuffer // + ); + + // + Copy( + xdonConditions.donOpenLowerBuffer, + conditions.donOpenLowerBuffer // + ); + + // + Copy( + xdonConditions.donHighUpperBuffer, + conditions.donHighUpperBuffer // + ); + + // + Copy( + xdonConditions.donHighLowerBuffer, + conditions.donHighLowerBuffer // + ); + + // + Copy( + xdonConditions.donLowUpperBuffer, + conditions.donLowUpperBuffer // + ); + + // + Copy( + xdonConditions.donLowLowerBuffer, + conditions.donLowLowerBuffer // + ); + + // + Copy( + xdonConditions.donCloseUpperBuffer, + conditions.donCloseUpperBuffer // + ); + + // + Copy( + xdonConditions.donCloseLowerBuffer, + conditions.donCloseLowerBuffer // + ); + + // + // Conditions ... + + // + conditions.isBreakedDonLowUpper = xdonConditions.isBreakedDonLowUpper; + conditions.isBreakedDonLowLower = xdonConditions.isBreakedDonLowLower; + conditions.isRejectedDonLowUpper = xdonConditions.isRejectedDonLowUpper; + conditions.isRejectedDonLowLower = xdonConditions.isRejectedDonLowLower; + conditions.isBreakedDonOpenUpper = xdonConditions.isBreakedDonOpenUpper; + conditions.isBreakedDonHighUpper = xdonConditions.isBreakedDonHighUpper; + conditions.isBreakedDonOpenLower = xdonConditions.isBreakedDonOpenLower; + conditions.isBreakedDonHighLower = xdonConditions.isBreakedDonHighLower; + conditions.isRejectedDonOpenUpper = xdonConditions.isRejectedDonOpenUpper; + conditions.isRejectedDonHighUpper = xdonConditions.isRejectedDonHighUpper; + conditions.isRejectedDonOpenLower = xdonConditions.isRejectedDonOpenLower; + conditions.isRejectedDonHighLower = xdonConditions.isRejectedDonHighLower; + conditions.isBreakedDonCloseUpper = xdonConditions.isBreakedDonCloseUpper; + conditions.isBreakedDonCloseLower = xdonConditions.isBreakedDonCloseLower; + conditions.isRejectedDonCloseUpper = xdonConditions.isRejectedDonCloseUpper; + conditions.isRejectedDonCloseLower = xdonConditions.isRejectedDonCloseLower; + + // + // X3MA ... + + // + // Buffers ... + + // + Copy( + x3maConditions.x3maFastBuffer, + conditions.x3maFastBuffer // + ); + + // + Copy( + x3maConditions.x3maMidBuffer, + conditions.x3maMidBuffer // + ); + + // + Copy( + x3maConditions.x3maSlowBuffer, + conditions.x3maSlowBuffer // + ); + + // + Copy( + x3maConditions.x3maFastStateBuffer, + conditions.x3maFastStateBuffer // + ); + + // + Copy( + x3maConditions.x3maMidStateBuffer, + conditions.x3maMidStateBuffer // + ); + + // + Copy( + x3maConditions.x3maSlowStateBuffer, + conditions.x3maSlowStateBuffer // + ); + + // + // Conditions ... + + // + conditions.isX3MaMidBullish = x3maConditions.isX3MaMidBullish; + conditions.isX3MaMidBearish = x3maConditions.isX3MaMidBearish; + conditions.isX3MaFastBullish = x3maConditions.isX3MaFastBullish; + conditions.isX3MaFastBearish = x3maConditions.isX3MaFastBearish; + conditions.isX3MaMidNeutural = x3maConditions.isX3MaMidNeutural; + conditions.isX3MaSlowBullish = x3maConditions.isX3MaSlowBullish; + conditions.isX3MaSlowBearish = x3maConditions.isX3MaSlowBearish; + conditions.isX3MaFastOverMid = x3maConditions.isX3MaFastOverMid; + conditions.isX3MaMidOverSlow = x3maConditions.isX3MaMidOverSlow; + conditions.isX3MaFastNeutural = x3maConditions.isX3MaFastNeutural; + conditions.isX3MaSlowNeutural = x3maConditions.isX3MaSlowNeutural; + conditions.isX3MaFastUnderMid = x3maConditions.isX3MaFastUnderMid; + conditions.isX3MaMidUnderSlow = x3maConditions.isX3MaMidUnderSlow; + conditions.isX3MaBullishState = x3maConditions.isX3MaBullishState; + conditions.isX3MaBearishState = x3maConditions.isX3MaBearishState; + conditions.isX3MaNeuturalState = x3maConditions.isX3MaNeuturalState; + conditions.isX3MaBullishOrdered = x3maConditions.isX3MaBullishOrdered; + conditions.isX3MaBearishOrdered = x3maConditions.isX3MaBearishOrdered; + conditions.isX3MaSwitchedToBullishState = x3maConditions.isX3MaSwitchedToBullishState; + conditions.isX3MaSwitchedToBearishState = x3maConditions.isX3MaSwitchedToBearishState; + conditions.isX3MaSwitchedToNeuturalState = x3maConditions.isX3MaSwitchedToNeuturalState; + conditions.isX3MaSwitchedToBullishOrdered = x3maConditions.isX3MaSwitchedToBullishOrdered; + conditions.isX3MaSwitchedToBearishOrdered = x3maConditions.isX3MaSwitchedToBearishOrdered; + + // + // XVWAP ... + + // + // Buffers ... + + // + Copy( + xvwapConditions.vwapFastBuffer, + conditions.vwapFastBuffer // + ); + + // + Copy( + xvwapConditions.vwapMidBuffer, + conditions.vwapMidBuffer // + ); + + // + Copy( + xvwapConditions.vwapSlowBuffer, + conditions.vwapSlowBuffer // + ); + + // + Copy( + xvwapConditions.vwapVolumeBuffer, + conditions.vwapVolumeBuffer // + ); + + // + Copy( + xvwapConditions.vwapPriceBuffer, + conditions.vwapPriceBuffer // + ); + + // + Copy( + xvwapConditions.vwapFastStateBuffer, + conditions.vwapFastStateBuffer // + ); + + // + Copy( + xvwapConditions.vwapMidStateBuffer, + conditions.vwapMidStateBuffer // + ); + + // + Copy( + xvwapConditions.vwapSlowStateBuffer, + conditions.vwapSlowStateBuffer // + ); + + // + // Conditions ... + + // + conditions.isVWapMidBullish = xvwapConditions.isVWapMidBullish; + conditions.isVWapMidBearish = xvwapConditions.isVWapMidBearish; + conditions.isVWapFastBullish = xvwapConditions.isVWapFastBullish; + conditions.isVWapFastBearish = xvwapConditions.isVWapFastBearish; + conditions.isVWapMidNeutural = xvwapConditions.isVWapMidNeutural; + conditions.isVWapSlowBullish = xvwapConditions.isVWapSlowBullish; + conditions.isVWapSlowBearish = xvwapConditions.isVWapSlowBearish; + conditions.isVWapFastOverMid = xvwapConditions.isVWapFastOverMid; + conditions.isVWapMidOverSlow = xvwapConditions.isVWapMidOverSlow; + conditions.isVWapFastNeutural = xvwapConditions.isVWapFastNeutural; + conditions.isVWapSlowNeutural = xvwapConditions.isVWapSlowNeutural; + conditions.isVWapFastUnderMid = xvwapConditions.isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = xvwapConditions.isVWapMidUnderSlow; + conditions.isVWapBullishState = xvwapConditions.isVWapBullishState; + conditions.isVWapBearishState = xvwapConditions.isVWapBearishState; + conditions.isVWapNeuturalState = xvwapConditions.isVWapNeuturalState; + conditions.isVWapBullishOrdered = xvwapConditions.isVWapBullishOrdered; + conditions.isVWapBearishOrdered = xvwapConditions.isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishState = xvwapConditions.isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = xvwapConditions.isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = xvwapConditions.isVWapSwitchedToNeuturalState; + conditions.isVWapSwitchedToBullishOrdered = xvwapConditions.isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = xvwapConditions.isVWapSwitchedToBearishOrdered; + + // + // Slopes ... + + // + double rsiSlope = GetSlope(conditions.rsiBuffer, pIDX, cIDX); + double strSlope = GetSlope(conditions.strBuffer, pIDX, cIDX); + double atrUpperSlope = GetSlope(conditions.atrUpperBuffer, pIDX, cIDX); + double atrLowerSlope = GetSlope(conditions.atrLowerBuffer, pIDX, cIDX); + double vwapFastSlope = GetSlope(conditions.vwapFastBuffer, pIDX, cIDX); + double vwapMidSlope = GetSlope(conditions.vwapMidBuffer, pIDX, cIDX); + double vwapSlowSlope = GetSlope(conditions.vwapSlowBuffer, pIDX, cIDX); + + // + bool isRsiSlopeBullish = rsiSlope > 0; + bool isStrSlopeBullish = strSlope > 0; + bool isAtrUpperSlopeBullish = atrUpperSlope > 0; + bool isAtrLowerSlopeBullish = atrLowerSlope > 0; + bool isVwapFastSlopeBullish = vwapFastSlope > 0; + bool isVwapMidSlopeBullish = vwapMidSlope > 0; + bool isVwapSlowSlopeBullish = vwapSlowSlope > 0; + + // + bool isRsiSlopeBearish = rsiSlope < 0; + bool isStrSlopeBearish = strSlope < 0; + bool isAtrUpperSlopeBearish = atrUpperSlope < 0; + bool isAtrLowerSlopeBearish = atrLowerSlope < 0; + bool isVwapFastSlopeBearish = vwapFastSlope < 0; + bool isVwapMidSlopeBearish = vwapMidSlope < 0; + bool isVwapSlowSlopeBearish = vwapSlowSlope < 0; + + // + conditions.rsiSlope = rsiSlope; + conditions.strSlope = strSlope; + conditions.vwapMidSlope = vwapMidSlope; + conditions.vwapSlowSlope = vwapSlowSlope; + conditions.atrUpperSlope = atrUpperSlope; + conditions.atrLowerSlope = atrLowerSlope; + conditions.vwapFastSlope = vwapFastSlope; + conditions.isRsiSlopeBearish = isRsiSlopeBearish; + conditions.isStrSlopeBearish = isStrSlopeBearish; + conditions.isRsiSlopeBullish = isRsiSlopeBullish; + conditions.isStrSlopeBullish = isStrSlopeBullish; + conditions.isVwapMidSlopeBearish = isVwapMidSlopeBearish; + conditions.isVwapMidSlopeBullish = isVwapMidSlopeBullish; + conditions.isAtrUpperSlopeBearish = isAtrUpperSlopeBearish; + conditions.isAtrLowerSlopeBearish = isAtrLowerSlopeBearish; + conditions.isVwapFastSlopeBearish = isVwapFastSlopeBearish; + conditions.isVwapSlowSlopeBearish = isVwapSlowSlopeBearish; + conditions.isAtrUpperSlopeBullish = isAtrUpperSlopeBullish; + conditions.isAtrLowerSlopeBullish = isAtrLowerSlopeBullish; + conditions.isVwapFastSlopeBullish = isVwapFastSlopeBullish; + conditions.isVwapSlowSlopeBullish = isVwapSlowSlopeBullish; + + // + // Complex Conditions ... + + // + double x3maFast = conditions.x3maFastBuffer[cIDX]; + double x3maMid = conditions.x3maMidBuffer[cIDX]; + double x3maSlow = conditions.x3maSlowBuffer[cIDX]; + + // + double x3mas[3] = { + x3maFast, + x3maMid, + x3maSlow // + }; + + // + double x3maMin = GetMin(x3mas); + double x3maMax = GetMax(x3mas); + + // + bool isX3MaMinBreakedUp = IsBarBreak( + x3maMin, + X_DIRECTION_BULLISH, + cBar // + ); + bool isX3MaMinBreakedDown = IsBarBreak( + x3maMin, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isX3MaMaxBreakedUp = IsBarBreak( + x3maMax, + X_DIRECTION_BULLISH, + cBar // + ); + bool isX3MaMaxBreakedDown = IsBarBreak( + x3maMax, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isX3MaFatsOverMid = conditions.x3maFastBuffer[cIDX] > conditions.x3maMidBuffer[cIDX]; + bool isX3MaFatsOverMidPrev = conditions.x3maFastBuffer[pIDX] > conditions.x3maMidBuffer[pIDX]; + + // + bool isX3MaFatsUnderMid = conditions.x3maFastBuffer[cIDX] < conditions.x3maMidBuffer[cIDX]; + bool isX3MaFatsUnderMidPrev = conditions.x3maFastBuffer[pIDX] < conditions.x3maMidBuffer[pIDX]; + + // + bool isX3MaFatsOverSlow = conditions.x3maFastBuffer[cIDX] > conditions.x3maSlowBuffer[cIDX]; + bool isX3MaFatsOverSlowPrev = conditions.x3maFastBuffer[pIDX] > conditions.x3maSlowBuffer[pIDX]; + + // + bool isX3MaFatsUnderSlow = conditions.x3maFastBuffer[cIDX] < conditions.x3maSlowBuffer[cIDX]; + bool isX3MaFatsUnderSlowPrev = conditions.x3maFastBuffer[pIDX] < conditions.x3maSlowBuffer[pIDX]; + + // + bool isX3MaFastCrossedOverMid = isX3MaFatsOverMid && + !isX3MaFatsOverMidPrev; + bool isX3MaFastCrossedUnderMid = isX3MaFatsUnderMid && + !isX3MaFatsUnderMidPrev; + + // + bool isX3MaFastCrossedOverSlow = isX3MaFatsOverSlow && + !isX3MaFatsOverSlowPrev; + bool isX3MaFastCrossedUnderSlow = isX3MaFatsUnderSlow && + !isX3MaFatsUnderSlowPrev; + + // + bool isClosedOverX3MaMin = cBar.close > x3maMin; + bool isClosedUnderX3MaMin = cBar.close < x3maMin; + + // + bool isClosedOverX3MaMax = cBar.close > x3maMax; + bool isClosedUnderX3MaMax = cBar.close < x3maMax; + + // + // + // + + // + double vwapFast = conditions.vwapFastBuffer[cIDX]; + double vwapMid = conditions.vwapMidBuffer[cIDX]; + double vwapSlow = conditions.vwapSlowBuffer[cIDX]; + + // + double vwaps[3] = { + vwapFast, + vwapMid, + vwapSlow // + }; + + // + double vwapMin = GetMin(vwaps); + double vwapMax = GetMax(vwaps); + + // + bool isVWapMinBreakedUp = IsBarBreak( + vwapMin, + X_DIRECTION_BULLISH, + cBar // + ); + bool isVWapMinBreakedDown = IsBarBreak( + vwapMin, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isVWapMaxBreakedUp = IsBarBreak( + vwapMax, + X_DIRECTION_BULLISH, + cBar // + ); + bool isVWapMaxBreakedDown = IsBarBreak( + vwapMax, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isVWapFatsOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFatsOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapFatsUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFatsUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapFatsOverSlow = conditions.vwapFastBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapFatsOverSlowPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFatsUnderSlow = conditions.vwapFastBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapFatsUnderSlowPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastCrossedOverMid = isVWapFatsOverMid && + !isVWapFatsOverMidPrev; + bool isVWapFastCrossedUnderMid = isVWapFatsUnderMid && + !isVWapFatsUnderMidPrev; + + // + bool isVWapFastCrossedOverSlow = isVWapFatsOverSlow && + !isVWapFatsOverSlowPrev; + bool isVWapFastCrossedUnderSlow = isVWapFatsUnderSlow && + !isVWapFatsUnderSlowPrev; + + // + bool isClosedOverVWapMin = cBar.close > vwapMin; + bool isClosedUnderVWapMin = cBar.close < vwapMin; + + // + bool isClosedOverVWapMax = cBar.close > vwapMax; + bool isClosedUnderVWapMax = cBar.close < vwapMax; + + // + bool isSarEqualsToPeak = + conditions.sarBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isSarEqualsToVale = + conditions.sarBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isSarIncreased = conditions.sarBuffer[cIDX] > conditions.sarBuffer[pIDX]; + bool isSarDecreased = conditions.sarBuffer[cIDX] < conditions.sarBuffer[pIDX]; + + // + double prevSar = conditions.sarBuffer[pIDX]; + double prevStr = conditions.strBuffer[pIDX]; + double prevCheLE1 = conditions.le1Buffer[pIDX]; + double prevCheLE2 = conditions.le2Buffer[pIDX]; + double prevCheSE1 = conditions.se1Buffer[pIDX]; + double prevCheSE2 = conditions.se2Buffer[pIDX]; + double prevAtrUpper = conditions.atrUpperBuffer[pIDX]; + double prevAtrLower = conditions.atrLowerBuffer[pIDX]; + + // + double ches[]; + if (prevCheLE1 != EMPTY_VALUE) + { + // + Add( + prevCheLE1, + ches // + ); + } + if (prevCheLE2 != EMPTY_VALUE) + { + // + Add( + prevCheLE2, + ches // + ); + } + if (prevCheSE1 != EMPTY_VALUE) + { + // + Add( + prevCheSE1, + ches // + ); + } + if (prevCheSE2 != EMPTY_VALUE) + { + // + Add( + prevCheSE2, + ches // + ); + } + + // + double cheMin = GetMin(ches); + double cheMax = GetMax(ches); + + // + bool isBreakedUpPrevSar = IsBarBreak( + prevSar, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevSar = IsBarBreak( + prevSar, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevStr = IsBarBreak( + prevStr, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevStr = IsBarBreak( + prevStr, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpPrevAtrUpper = IsBarReject( + prevAtrUpper, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isRejectedDownPrevAtrUpper = IsBarReject( + prevAtrUpper, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpPrevAtrLower = IsBarReject( + prevAtrLower, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isRejectedDownPrevAtrLower = IsBarReject( + prevAtrLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevAtrUpper = IsBarBreak( + prevAtrUpper, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevAtrUpper = IsBarBreak( + prevAtrUpper, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevAtrLower = IsBarBreak( + prevAtrLower, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevAtrLower = IsBarBreak( + prevAtrLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheLE1 = IsBarBreak( + prevCheLE1, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheLE2 = IsBarBreak( + prevCheLE2, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheSE1 = IsBarBreak( + prevCheSE1, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheSE2 = IsBarBreak( + prevCheSE2, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isBreakedDownPrevCheLE1 = IsBarBreak( + prevCheLE1, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheLE2 = IsBarBreak( + prevCheLE2, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheSE1 = IsBarBreak( + prevCheSE1, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheSE2 = IsBarBreak( + prevCheSE2, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheMin = IsBarBreak( + cheMin, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevCheMin = IsBarBreak( + cheMin, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheMax = IsBarBreak( + cheMax, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevCheMax = IsBarBreak( + cheMax, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isSarCrossedUnderPeak = + conditions.sarBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.sarBuffer[pIDX] < conditions.peaksBuffer[pIDX]); + bool isSarCrossedOverVale = + conditions.sarBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.sarBuffer[pIDX] > conditions.valesBuffer[pIDX]); + + // + bool isStrEqualsToPeak = + conditions.strBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isStrEqualsToVale = + conditions.strBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isStrCrossedUnderPeak = + conditions.strBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.strBuffer[pIDX] < conditions.peaksBuffer[pIDX]); + bool isStrCrossedOverVale = + conditions.strBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.strBuffer[pIDX] > conditions.valesBuffer[pIDX]); + + // + bool isPeakOverAtrUpper = + conditions.peaksBuffer[cIDX] > conditions.atrUpperBuffer[cIDX]; + bool isValeUnderAtrLower = + conditions.valesBuffer[cIDX] > conditions.atrLowerBuffer[cIDX]; + + // + bool isNewPeakOverAtrUpper = + isPeakOverAtrUpper && + conditions.isNewPeak; + bool isNewValeUnderAtrLower = + isValeUnderAtrLower && + conditions.isNewVale; + + // + bool isStrUpperOverPeak = + conditions.strBuffer[cIDX] > conditions.peaksBuffer[cIDX]; + bool isStrUpperOverPeakPrev = + conditions.strBuffer[pIDX] > conditions.peaksBuffer[pIDX]; + + // + bool isStrUpperUnderPeak = + conditions.strBuffer[cIDX] < conditions.peaksBuffer[cIDX]; + bool isStrUpperUnderPeakPrev = + conditions.strBuffer[pIDX] < conditions.peaksBuffer[pIDX]; + + // + bool isStrUpperCrossedOverPeak = isStrUpperOverPeak && + !isStrUpperOverPeakPrev; + bool isStrUpperCrossedUnderPeak = isStrUpperUnderPeak && + !isStrUpperUnderPeakPrev; + + // + bool isStrLowerOverVale = + conditions.strBuffer[cIDX] > conditions.valesBuffer[cIDX]; + bool isStrLowerOverValePrev = + conditions.strBuffer[pIDX] > conditions.valesBuffer[pIDX]; + + // + bool isStrLowerUnderVale = + conditions.strBuffer[cIDX] < conditions.valesBuffer[cIDX]; + bool isStrLowerUnderValePrev = + conditions.strBuffer[pIDX] < conditions.valesBuffer[pIDX]; + + // + bool isStrLowerCrossedOverVale = isStrLowerOverVale && + !isStrLowerOverValePrev; + bool isStrLowerCrossedUnderVale = isStrLowerUnderVale && + !isStrLowerUnderValePrev; + + // + bool isDonHighUpperEqualsToPeak = + conditions.donHighUpperBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isDonLowLowerEqualsToVale = + conditions.donLowLowerBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isStrUpperOverAtrUpper = + conditions.strUpBuffer[cIDX] > conditions.atrUpperBuffer[cIDX]; + bool isStrUpperOverAtrUpperPrev = + conditions.strUpBuffer[pIDX] > conditions.atrUpperBuffer[pIDX]; + bool isStrUpperCrossedOverAtrUpper = isStrUpperOverAtrUpper && + !isStrUpperOverAtrUpperPrev; + + // + bool isStrUpperUnderAtrUpper = + conditions.strUpBuffer[cIDX] < conditions.atrUpperBuffer[cIDX]; + bool isStrUpperUnderAtrUpperPrev = + conditions.strUpBuffer[pIDX] < conditions.atrUpperBuffer[pIDX]; + bool isStrUpperCrossedUnderAtrUpper = isStrUpperUnderAtrUpper && + !isStrUpperUnderAtrUpperPrev; + + // + bool isStrLowerOverAtrLower = + conditions.strDownBuffer[cIDX] > conditions.atrLowerBuffer[cIDX]; + bool isStrLowerOverAtrLowerPrev = + conditions.strDownBuffer[pIDX] > conditions.atrLowerBuffer[pIDX]; + bool isStrLowerCrossedOverAtrLower = isStrLowerOverAtrLower && + !isStrLowerOverAtrLowerPrev; + + // + bool isStrLowerUnderAtrLower = + conditions.strDownBuffer[cIDX] < conditions.atrLowerBuffer[cIDX]; + bool isStrLowerUnderAtrLowerPrev = + conditions.strDownBuffer[pIDX] < conditions.atrLowerBuffer[pIDX]; + bool isStrLowerCrossedUnderAtrLower = isStrLowerUnderAtrLower && + !isStrLowerUnderAtrLowerPrev; + + // + bool isStrUpperOverDonHighUpper = + conditions.strUpBuffer[cIDX] > conditions.donHighUpperBuffer[cIDX]; + bool isStrUpperOverDonHighUpperPrev = + conditions.strUpBuffer[pIDX] > conditions.donHighUpperBuffer[pIDX]; + bool isStrUpperCrossedOverDonHighUpper = isStrUpperOverDonHighUpper && + !isStrUpperOverDonHighUpperPrev; + + // + bool isStrUpperUnderDonHighUpper = + conditions.strUpBuffer[cIDX] < conditions.donHighUpperBuffer[cIDX]; + bool isStrUpperUnderDonHighUpperPrev = + conditions.strUpBuffer[pIDX] < conditions.donHighUpperBuffer[pIDX]; + bool isStrUpperCrossedUnderDonHighUpper = isStrUpperUnderDonHighUpper && + !isStrUpperUnderDonHighUpperPrev; + + // + bool isStrLowerOverDonLowLower = + conditions.strDownBuffer[cIDX] > conditions.donLowLowerBuffer[cIDX]; + bool isStrLowerOverDonLowLowerPrev = + conditions.strDownBuffer[pIDX] > conditions.donLowLowerBuffer[pIDX]; + bool isStrLowerCrossedOverDonLowLower = isStrLowerOverDonLowLower && + !isStrLowerOverDonLowLowerPrev; + + // + bool isStrLowerUnderDonLowLower = + conditions.strDownBuffer[cIDX] < conditions.donLowLowerBuffer[cIDX]; + bool isStrLowerUnderDonLowLowerPrev = + conditions.strDownBuffer[pIDX] < conditions.donLowLowerBuffer[pIDX]; + bool isStrLowerCrossedUnderDonLowLower = isStrLowerUnderDonLowLower && + !isStrLowerUnderDonLowLowerPrev; + + // + bool isAtrUpperOverPeak = conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX]; + bool isAtrUpperEqualsToPeak = conditions.atrUpperBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + + // + bool isAtrUpperCrossedUpPeak = conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX]); + bool isAtrUpperCrossedDownPeak = conditions.atrUpperBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] < conditions.peaksBuffer[cIDX]); + + // + bool isAtrLowerUnderVale = conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX]; + bool isAtrLowerEqualsToVale = conditions.atrUpperBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isAtrLowerCrossedUpVale = conditions.atrUpperBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] > conditions.valesBuffer[cIDX]); + bool isAtrLowerCrossedDownVale = conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX]); + + // + conditions.cheMin = cheMin; + conditions.cheMax = cheMax; + conditions.x3maMin = x3maMin; + conditions.x3maMax = x3maMax; + conditions.vwapMin = vwapMin; + conditions.vwapMax = vwapMax; + + // + conditions.isSarIncreased = isSarIncreased; + conditions.isSarDecreased = isSarDecreased; + conditions.isSarEqualsToPeak = isSarEqualsToPeak; + conditions.isSarEqualsToVale = isSarEqualsToVale; + conditions.isStrEqualsToPeak = isStrEqualsToPeak; + conditions.isStrEqualsToVale = isStrEqualsToVale; + conditions.isX3MaFatsOverMid = isX3MaFatsOverMid; + conditions.isX3MaMinBreakedUp = isX3MaMinBreakedUp; + conditions.isX3MaMaxBreakedUp = isX3MaMaxBreakedUp; + conditions.isX3MaFatsUnderMid = isX3MaFatsUnderMid; + conditions.isX3MaFatsOverSlow = isX3MaFatsOverSlow; + conditions.isStrUpperOverPeak = isStrUpperOverPeak; + conditions.isPeakOverAtrUpper = isPeakOverAtrUpper; + conditions.isStrLowerOverVale = isStrLowerOverVale; + conditions.isVWapMinBreakedUp = isVWapMinBreakedUp; + conditions.isVWapMaxBreakedUp = isVWapMaxBreakedUp; + conditions.isBreakedUpPrevSar = isBreakedUpPrevSar; + conditions.isBreakedUpPrevStr = isBreakedUpPrevStr; + conditions.isAtrUpperOverPeak = isAtrUpperOverPeak; + conditions.isClosedOverX3MaMin = isClosedOverX3MaMin; + conditions.isClosedOverX3MaMax = isClosedOverX3MaMax; + conditions.isX3MaFatsUnderSlow = isX3MaFatsUnderSlow; + conditions.isAtrLowerUnderVale = isAtrLowerUnderVale; + conditions.isStrLowerUnderVale = isStrLowerUnderVale; + conditions.isStrUpperUnderPeak = isStrUpperUnderPeak; + conditions.isValeUnderAtrLower = isValeUnderAtrLower; + conditions.isClosedOverVWapMin = isClosedOverVWapMin; + conditions.isClosedOverVWapMax = isClosedOverVWapMax; + conditions.isClosedUnderX3MaMin = isClosedUnderX3MaMin; + conditions.isClosedUnderX3MaMax = isClosedUnderX3MaMax; + conditions.isX3MaMinBreakedDown = isX3MaMinBreakedDown; + conditions.isX3MaMaxBreakedDown = isX3MaMaxBreakedDown; + conditions.isClosedUnderVWapMin = isClosedUnderVWapMin; + conditions.isClosedUnderVWapMax = isClosedUnderVWapMax; + conditions.isVWapMinBreakedDown = isVWapMinBreakedDown; + conditions.isVWapMaxBreakedDown = isVWapMaxBreakedDown; + conditions.isSarCrossedOverVale = isSarCrossedOverVale; + conditions.isStrCrossedOverVale = isStrCrossedOverVale; + conditions.isBreakedDownPrevStr = isBreakedDownPrevStr; + conditions.isBreakedDownPrevSar = isBreakedDownPrevSar; + conditions.isX3MaFatsOverMidPrev = isX3MaFatsOverMidPrev; + conditions.isSarCrossedUnderPeak = isSarCrossedUnderPeak; + conditions.isStrCrossedUnderPeak = isStrCrossedUnderPeak; + conditions.isNewPeakOverAtrUpper = isNewPeakOverAtrUpper; + conditions.isBreakedUpPrevCheLE1 = isBreakedUpPrevCheLE1; + conditions.isBreakedUpPrevCheLE2 = isBreakedUpPrevCheLE2; + conditions.isBreakedUpPrevCheSE1 = isBreakedUpPrevCheSE1; + conditions.isBreakedUpPrevCheSE2 = isBreakedUpPrevCheSE2; + conditions.isBreakedUpPrevCheMin = isBreakedUpPrevCheMin; + conditions.isBreakedUpPrevCheMax = isBreakedUpPrevCheMax; + conditions.isX3MaFatsUnderMidPrev = isX3MaFatsUnderMidPrev; + conditions.isX3MaFatsOverSlowPrev = isX3MaFatsOverSlowPrev; + conditions.isAtrUpperEqualsToPeak = isAtrUpperEqualsToPeak; + conditions.isAtrLowerEqualsToVale = isAtrLowerEqualsToVale; + conditions.isNewValeUnderAtrLower = isNewValeUnderAtrLower; + conditions.isStrUpperOverAtrUpper = isStrUpperOverAtrUpper; + conditions.isStrLowerOverAtrLower = isStrLowerOverAtrLower; + conditions.isX3MaFatsUnderSlowPrev = isX3MaFatsUnderSlowPrev; + conditions.isBreakedDownPrevCheMin = isBreakedDownPrevCheMin; + conditions.isBreakedDownPrevCheMax = isBreakedDownPrevCheMax; + conditions.isBreakedDownPrevCheLE1 = isBreakedDownPrevCheLE1; + conditions.isBreakedDownPrevCheLE2 = isBreakedDownPrevCheLE2; + conditions.isBreakedDownPrevCheSE1 = isBreakedDownPrevCheSE1; + conditions.isBreakedDownPrevCheSE2 = isBreakedDownPrevCheSE2; + conditions.isStrUpperUnderAtrUpper = isStrUpperUnderAtrUpper; + conditions.isStrLowerUnderAtrLower = isStrLowerUnderAtrLower; + conditions.isBreakedUpPrevAtrUpper = isBreakedUpPrevAtrUpper; + conditions.isBreakedUpPrevAtrLower = isBreakedUpPrevAtrLower; + conditions.isAtrUpperCrossedUpPeak = isAtrUpperCrossedUpPeak; + conditions.isAtrLowerCrossedUpVale = isAtrLowerCrossedUpVale; + conditions.isX3MaFastCrossedOverMid = isX3MaFastCrossedOverMid; + conditions.isVWapFastCrossedOverMid = isVWapFastCrossedOverMid; + conditions.isRejectedUpPrevAtrUpper = isRejectedUpPrevAtrUpper; + conditions.isRejectedUpPrevAtrLower = isRejectedUpPrevAtrLower; + conditions.isX3MaFastCrossedUnderMid = isX3MaFastCrossedUnderMid; + conditions.isX3MaFastCrossedOverSlow = isX3MaFastCrossedOverSlow; + conditions.isAtrUpperCrossedDownPeak = isAtrUpperCrossedDownPeak; + conditions.isAtrLowerCrossedDownVale = isAtrLowerCrossedDownVale; + conditions.isBreakedDownPrevAtrUpper = isBreakedDownPrevAtrUpper; + conditions.isBreakedDownPrevAtrLower = isBreakedDownPrevAtrLower; + conditions.isVWapFastCrossedUnderMid = isVWapFastCrossedUnderMid; + conditions.isDonLowLowerEqualsToVale = isDonLowLowerEqualsToVale; + conditions.isStrUpperCrossedOverPeak = isStrUpperCrossedOverPeak; + conditions.isStrLowerCrossedOverVale = isStrLowerCrossedOverVale; + conditions.isStrLowerOverDonLowLower = isStrLowerOverDonLowLower; + conditions.isVWapFastCrossedOverSlow = isVWapFastCrossedOverSlow; + conditions.isX3MaFastCrossedUnderSlow = isX3MaFastCrossedUnderSlow; + conditions.isRejectedDownPrevAtrUpper = isRejectedDownPrevAtrUpper; + conditions.isRejectedDownPrevAtrLower = isRejectedDownPrevAtrLower; + conditions.isVWapFastCrossedUnderSlow = isVWapFastCrossedUnderSlow; + conditions.isStrUpperOverDonHighUpper = isStrUpperOverDonHighUpper; + conditions.isStrLowerUnderDonLowLower = isStrLowerUnderDonLowLower; + conditions.isDonHighUpperEqualsToPeak = isDonHighUpperEqualsToPeak; + conditions.isStrUpperCrossedUnderPeak = isStrUpperCrossedUnderPeak; + conditions.isStrLowerCrossedUnderVale = isStrLowerCrossedUnderVale; + conditions.isStrUpperUnderDonHighUpper = isStrUpperUnderDonHighUpper; + conditions.isStrLowerCrossedOverAtrLower = isStrLowerCrossedOverAtrLower; + conditions.isStrUpperCrossedOverAtrUpper = isStrUpperCrossedOverAtrUpper; + conditions.isStrUpperCrossedUnderAtrUpper = isStrUpperCrossedUnderAtrUpper; + conditions.isStrLowerCrossedUnderAtrLower = isStrLowerCrossedUnderAtrLower; + conditions.isStrLowerCrossedOverDonLowLower = isStrLowerCrossedOverDonLowLower; + conditions.isStrUpperCrossedOverDonHighUpper = isStrUpperCrossedOverDonHighUpper; + conditions.isStrLowerCrossedUnderDonLowLower = isStrLowerCrossedUnderDonLowLower; + conditions.isStrUpperCrossedUnderDonHighUpper = isStrUpperCrossedUnderDonHighUpper; + + // + xpvConditions.Clean(); + xhkConditions.Clean(); + xatrConditions.Clean(); + xstrConditions.Clean(); + xcheConditions.Clean(); + xdonConditions.Clean(); + x3maConditions.Clean(); + xvwapConditions.Clean(); + xtrendConditions.Clean(); + + // + Free(); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + string mSymbol; // Trading Symbol + ENUM_TIMEFRAMES mPeriod; // Trading Period + + // + // Inputs ... + X121Inputs mInputs; + X121XPVInputs xpvInputs; + X121XHKInputs xhkInputs; + X121XATRInputs xatrInputs; + X121XDONInputs xdonInputs; + X121XSTRInputs xstrInputs; + X121XCHEInputs xcheInputs; + X121X3MAInputs x3maInputs; + X121XVWAPInputs xvwapInputs; + X121XTRENDInputs xtrendInputs; + + // + int mRSIHandler; +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.x3ma.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.x3ma.helper.mq5 new file mode 100644 index 0000000..8337273 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.x3ma.helper.mq5 @@ -0,0 +1,1339 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121X3MAHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_X3MA_BUFFERS +{ + // + X121_X3MA_FAST_LINE = 0, + X121_X3MA_FAST_STATE_LINE = 6, + X121_X3MA_MID_LINE = 2, + X121_X3MA_MID_STATE_LINE = 7, + X121_X3MA_SLOW_LINE = 4, + X121_X3MA_SLOW_STATE_LINE = 8, +}; + +// +enum ENUM_X3MA_STATES +{ + X3MA_STATE_BULLISH = 1, + X3MA_STATE_BEARISH = 2, + X3MA_STATE_NEUTURAL = 3, +}; + +// +// Input Models ... +struct X121X3MAInputs +{ + // + // Props ... + int x3maFastMALength; // Fast MA Length + int x3maMidMALength; // Mid MA Length + int x3maSlowMALength; // Slow MA Length + ENUM_MA_METHOD x3maMaMethod; // MA Method + ENUM_APPLIED_PRICE x3maMaAppliedTo; // Applied To + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showX3MaFast; // Show X3Ma Fast + bool showX3MaMid; // Show X3Ma Medium + bool showX3MaSlow; // Show X3Ma Slow + + // + // Constructor(s) ... + X121X3MAInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + x3maFastMALength = 0; + x3maMidMALength = 0; + x3maSlowMALength = 0; + x3maMaMethod = MODE_EMA; + x3maMaAppliedTo = PRICE_CLOSE; + startCalculationForLastBars = 0; + showX3MaFast = false; + showX3MaMid = false; + showX3MaSlow = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + x3maFastMALength = 20; + x3maMidMALength = 50; + x3maSlowMALength = 200; + x3maMaMethod = MODE_EMA; + x3maMaAppliedTo = PRICE_CLOSE; + startCalculationForLastBars = 1000; + showX3MaFast = true; + showX3MaMid = true; + showX3MaSlow = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + x3maFastMALength > 2 && + x3maMidMALength > x3maFastMALength && + x3maSlowMALength > x3maMidMALength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(x3maFastMALength, x3maMidMALength); + result = MathMax(result, x3maSlowMALength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121X3MAConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double x3maFastBuffer[]; + double x3maMidBuffer[]; + double x3maSlowBuffer[]; + double x3maFastStateBuffer[]; + double x3maMidStateBuffer[]; + double x3maSlowStateBuffer[]; + + // + // Conditions ... + + // + bool isX3MaFastBullish; + bool isX3MaFastBearish; + bool isX3MaFastNeutural; + + // + bool isX3MaMidBullish; + bool isX3MaMidBearish; + bool isX3MaMidNeutural; + + // + bool isX3MaSlowBullish; + bool isX3MaSlowBearish; + bool isX3MaSlowNeutural; + + // + bool isX3MaFastOverMid; + bool isX3MaMidOverSlow; + + // + bool isX3MaFastUnderMid; + bool isX3MaMidUnderSlow; + + // + bool isX3MaBullishState; + bool isX3MaBearishState; + bool isX3MaNeuturalState; + + // + bool isX3MaBullishOrdered; + bool isX3MaBearishOrdered; + + // + bool isX3MaSwitchedToBullishOrdered; + bool isX3MaSwitchedToBearishOrdered; + + // + bool isX3MaSwitchedToBullishState; + bool isX3MaSwitchedToBearishState; + bool isX3MaSwitchedToNeuturalState; + + // + // Constructor ... + X121X3MAConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(x3maFastBuffer); + Clean(x3maMidBuffer); + Clean(x3maSlowBuffer); + Clean(x3maFastStateBuffer); + Clean(x3maMidStateBuffer); + Clean(x3maSlowStateBuffer); + + // + ArraySetAsSeries(x3maFastBuffer, true); + ArraySetAsSeries(x3maMidBuffer, true); + ArraySetAsSeries(x3maSlowBuffer, true); + ArraySetAsSeries(x3maFastStateBuffer, true); + ArraySetAsSeries(x3maMidStateBuffer, true); + ArraySetAsSeries(x3maSlowStateBuffer, true); + + // + // Conditions ... + + // + isX3MaFastBullish = false; + isX3MaFastBearish = false; + isX3MaFastNeutural = false; + + // + isX3MaMidBullish = false; + isX3MaMidBearish = false; + isX3MaMidNeutural = false; + + // + isX3MaSlowBullish = false; + isX3MaSlowBearish = false; + isX3MaSlowNeutural = false; + + // + isX3MaFastOverMid = false; + isX3MaMidOverSlow = false; + + // + isX3MaFastUnderMid = false; + isX3MaMidUnderSlow = false; + + // + isX3MaBullishState = false; + isX3MaBearishState = false; + isX3MaNeuturalState = false; + + // + isX3MaBullishOrdered = false; + isX3MaBearishOrdered = false; + + // + isX3MaSwitchedToBullishOrdered = false; + isX3MaSwitchedToBearishOrdered = false; + + // + isX3MaSwitchedToBullishState = false; + isX3MaSwitchedToBearishState = false; + isX3MaSwitchedToNeuturalState = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isX3MaFastBullish", isX3MaFastBullish, ignoreFalseConditions, separator) + + ToString("isX3MaFastBearish", isX3MaFastBearish, ignoreFalseConditions, separator) + + ToString("isX3MaFastNeutural", isX3MaFastNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaMidBullish", isX3MaMidBullish, ignoreFalseConditions, separator) + + ToString("isX3MaMidBearish", isX3MaMidBearish, ignoreFalseConditions, separator) + + ToString("isX3MaMidNeutural", isX3MaMidNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaSlowBullish", isX3MaSlowBullish, ignoreFalseConditions, separator) + + ToString("isX3MaSlowBearish", isX3MaSlowBearish, ignoreFalseConditions, separator) + + ToString("isX3MaSlowNeutural", isX3MaSlowNeutural, ignoreFalseConditions, separator) + + ToString("isX3MaFastOverMid", isX3MaFastOverMid, ignoreFalseConditions, separator) + + ToString("isX3MaMidOverSlow", isX3MaMidOverSlow, ignoreFalseConditions, separator) + + ToString("isX3MaFastUnderMid", isX3MaFastUnderMid, ignoreFalseConditions, separator) + + ToString("isX3MaMidUnderSlow", isX3MaMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isX3MaBullishState", isX3MaBullishState, ignoreFalseConditions, separator) + + ToString("isX3MaBearishState", isX3MaBearishState, ignoreFalseConditions, separator) + + ToString("isX3MaNeuturalState", isX3MaNeuturalState, ignoreFalseConditions, separator) + + ToString("isX3MaBullishOrdered", isX3MaBullishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaBearishOrdered", isX3MaBearishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBullishOrdered", isX3MaSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBearishOrdered", isX3MaSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBullishState", isX3MaSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToBearishState", isX3MaSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isX3MaSwitchedToNeuturalState", isX3MaSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121X3MAHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121X3MAHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121X3MAHelper() + { + // + mInputs.Clean(); + + // + Clean(x3maFastBuffer); + Clean(x3maMidBuffer); + Clean(x3maSlowBuffer); + Clean(x3maFastStateBuffer); + Clean(x3maMidStateBuffer); + Clean(x3maSlowStateBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121X3MAInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(x3maFastBuffer, true); + ArraySetAsSeries(x3maMidBuffer, true); + ArraySetAsSeries(x3maSlowBuffer, true); + ArraySetAsSeries(x3maFastStateBuffer, true); + ArraySetAsSeries(x3maMidStateBuffer, true); + ArraySetAsSeries(x3maSlowStateBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.x3ma", + // + // Inputs ... + // + // Market ... + "", + mInputs.x3maFastMALength, + mInputs.x3maMidMALength, + mInputs.x3maSlowMALength, + mInputs.x3maMaMethod, + mInputs.x3maMaAppliedTo, + // + // Presentation ... + "", + // + mInputs.startCalculationForLastBars, + // + mInputs.showX3MaFast, + mInputs.showX3MaMid, + mInputs.showX3MaSlow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121X3MAInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121X3MAInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // FAST ... + + // + double GetX3MaFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maFastBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maFastBuffer[barIndex]; + } + + // + int CopyX3MaFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maFastBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE FAST ... + + // + double GetX3MaFastState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maFastStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maFastStateBuffer[barIndex]; + } + + // + int CopyX3MaFastState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maFastStateBuffer, + buffer, + forceClean + // + ); + } + + // + // MID ... + + // + double GetX3MaMid( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maMidBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maMidBuffer[barIndex]; + } + + // + int CopyX3MaMid( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maMidBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE MID ... + + // + double GetX3MaMidState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maMidStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maMidStateBuffer[barIndex]; + } + + // + int CopyX3MaMidState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maMidStateBuffer, + buffer, + forceClean + // + ); + } + + // + // SLOW ... + + // + double GetX3MaSlowBuffer( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maSlowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maSlowBuffer[barIndex]; + } + + // + int CopyX3MaSlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maSlowBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE SLOW ... + + // + double GetX3MaSlowState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(x3maSlowStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return x3maSlowStateBuffer[barIndex]; + } + + // + int CopyX3MaSlowState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + x3maSlowStateBuffer, + buffer, + forceClean + // + ); + } + + // + // Converts to State ... + ENUM_X3MA_STATES ToX3MAState(double value) + { + // + ENUM_X3MA_STATES result = + value == 1 + ? X3MA_STATE_BULLISH + : value == 2 + ? X3MA_STATE_BEARISH + : X3MA_STATE_NEUTURAL; + + // + return result; + } + + // + bool IsX3MABullish(double value) + { + // + bool result = false; + + // + result = ToX3MAState(value) == X3MA_STATE_BULLISH; + + // + return result; + } + + // + bool IsX3MABearish(double value) + { + // + bool result = false; + + // + result = ToX3MAState(value) == X3MA_STATE_BEARISH; + + // + return result; + } + + // + bool IsX3MANeutural(double value) + { + // + bool result = false; + + // + result = ToX3MAState(value) == X3MA_STATE_NEUTURAL; + + // + return result; + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121X3MAConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyX3MaFast( + zIndex, + loopback, + conditions.x3maFastBuffer // + ); + + // + CopyX3MaFastState( + zIndex, + loopback, + conditions.x3maFastStateBuffer // + ); + + // + CopyX3MaMid( + zIndex, + loopback, + conditions.x3maMidBuffer // + ); + + // + CopyX3MaMidState( + zIndex, + loopback, + conditions.x3maMidStateBuffer // + ); + + // + CopyX3MaSlow( + zIndex, + loopback, + conditions.x3maSlowBuffer // + ); + + // + CopyX3MaSlowState( + zIndex, + loopback, + conditions.x3maSlowStateBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // SAR ... + + // + bool isX3MaFastBullish = IsX3MABullish(conditions.x3maFastStateBuffer[cIDX]); + bool isX3MaFastBullishPrev = IsX3MABullish(conditions.x3maFastStateBuffer[pIDX]); + + // + bool isX3MaFastBearish = IsX3MABearish(conditions.x3maFastStateBuffer[cIDX]); + bool isX3MaFastBearishPrev = IsX3MABearish(conditions.x3maFastStateBuffer[pIDX]); + + // + bool isX3MaFastNeutural = IsX3MANeutural(conditions.x3maFastStateBuffer[cIDX]); + bool isX3MaFastNeuturalPrev = IsX3MANeutural(conditions.x3maFastStateBuffer[pIDX]); + + // + bool isX3MaMidBullish = IsX3MABullish(conditions.x3maMidStateBuffer[cIDX]); + bool isX3MaMidBullishPrev = IsX3MABullish(conditions.x3maMidStateBuffer[pIDX]); + + // + bool isX3MaMidBearish = IsX3MABearish(conditions.x3maMidStateBuffer[cIDX]); + bool isX3MaMidBearishPrev = IsX3MABearish(conditions.x3maMidStateBuffer[pIDX]); + + // + bool isX3MaMidNeutural = IsX3MANeutural(conditions.x3maMidStateBuffer[cIDX]); + bool isX3MaMidNeuturalPrev = IsX3MANeutural(conditions.x3maMidStateBuffer[pIDX]); + + // + bool isX3MaSlowBullish = IsX3MABullish(conditions.x3maSlowStateBuffer[cIDX]); + bool isX3MaSlowBullishPrev = IsX3MABullish(conditions.x3maSlowStateBuffer[pIDX]); + + // + bool isX3MaSlowBearish = IsX3MABearish(conditions.x3maSlowStateBuffer[cIDX]); + bool isX3MaSlowBearishPrev = IsX3MABearish(conditions.x3maSlowStateBuffer[pIDX]); + + // + bool isX3MaSlowNeutural = IsX3MANeutural(conditions.x3maSlowStateBuffer[cIDX]); + bool isX3MaSlowNeuturalPrev = IsX3MANeutural(conditions.x3maSlowStateBuffer[pIDX]); + + // + bool isX3MaFastOverMid = conditions.x3maFastBuffer[cIDX] > conditions.x3maMidBuffer[cIDX]; + bool isX3MaFastOverMidPrev = conditions.x3maFastBuffer[pIDX] > conditions.x3maMidBuffer[pIDX]; + + // + bool isX3MaMidOverSlow = conditions.x3maMidBuffer[cIDX] > conditions.x3maSlowBuffer[cIDX]; + bool isX3MaMidOverSlowPrev = conditions.x3maMidBuffer[pIDX] > conditions.x3maSlowBuffer[pIDX]; + + // + bool isX3MaFastUnderMid = conditions.x3maFastBuffer[cIDX] < conditions.x3maMidBuffer[cIDX]; + bool isX3MaFastUnderMidPrev = conditions.x3maFastBuffer[pIDX] < conditions.x3maMidBuffer[pIDX]; + + // + bool isX3MaMidUnderSlow = conditions.x3maMidBuffer[cIDX] < conditions.x3maSlowBuffer[cIDX]; + bool isX3MaMidUnderSlowPrev = conditions.x3maMidBuffer[pIDX] < conditions.x3maSlowBuffer[pIDX]; + + // + bool isX3MaBullishState = isX3MaFastBullish && + isX3MaMidBullish && + isX3MaSlowBullish; + bool isX3MaBullishStatePrev = isX3MaFastBullishPrev && + isX3MaMidBullishPrev && + isX3MaSlowBullishPrev; + + // + bool isX3MaBearishState = isX3MaFastBearish && + isX3MaMidBearish && + isX3MaSlowBearish; + bool isX3MaBearishStatePrev = isX3MaFastBearishPrev && + isX3MaMidBearishPrev && + isX3MaSlowBearishPrev; + + // + bool isX3MaNeuturalState = isX3MaFastNeutural && + isX3MaMidNeutural && + isX3MaSlowNeutural; + bool isX3MaNeuturalStatePrev = isX3MaFastNeuturalPrev && + isX3MaMidNeuturalPrev && + isX3MaSlowNeuturalPrev; + + // + bool isX3MaBullishOrdered = isX3MaFastOverMid && + isX3MaMidOverSlow; + bool isX3MaBullishOrderedPrev = isX3MaFastOverMidPrev && + isX3MaMidOverSlowPrev; + + // + bool isX3MaBearishOrdered = isX3MaFastUnderMid && + isX3MaMidUnderSlow; + bool isX3MaBearishOrderedPrev = isX3MaFastUnderMidPrev && + isX3MaMidUnderSlowPrev; + + // + bool isX3MaSwitchedToBullishOrdered = isX3MaBullishOrdered && + !isX3MaBullishOrderedPrev; + bool isX3MaSwitchedToBearishOrdered = isX3MaBearishOrdered && + !isX3MaBearishOrderedPrev; + + // + bool isX3MaSwitchedToBullishState = isX3MaBullishState && + !isX3MaBullishStatePrev; + bool isX3MaSwitchedToBearishState = isX3MaBearishState && + !isX3MaBearishStatePrev; + bool isX3MaSwitchedToNeuturalState = isX3MaNeuturalState && + !isX3MaNeuturalStatePrev; + + // + conditions.isX3MaFastBullish = isX3MaFastBullish; + conditions.isX3MaFastBearish = isX3MaFastBearish; + conditions.isX3MaFastNeutural = isX3MaFastNeutural; + conditions.isX3MaMidBullish = isX3MaMidBullish; + conditions.isX3MaMidBearish = isX3MaMidBearish; + conditions.isX3MaMidNeutural = isX3MaMidNeutural; + conditions.isX3MaSlowBullish = isX3MaSlowBullish; + conditions.isX3MaSlowBearish = isX3MaSlowBearish; + conditions.isX3MaSlowNeutural = isX3MaSlowNeutural; + conditions.isX3MaFastOverMid = isX3MaFastOverMid; + conditions.isX3MaMidOverSlow = isX3MaMidOverSlow; + conditions.isX3MaFastUnderMid = isX3MaFastUnderMid; + conditions.isX3MaMidUnderSlow = isX3MaMidUnderSlow; + conditions.isX3MaBullishState = isX3MaBullishState; + conditions.isX3MaBearishState = isX3MaBearishState; + conditions.isX3MaNeuturalState = isX3MaNeuturalState; + conditions.isX3MaBullishOrdered = isX3MaBullishOrdered; + conditions.isX3MaBearishOrdered = isX3MaBearishOrdered; + conditions.isX3MaSwitchedToBullishOrdered = isX3MaSwitchedToBullishOrdered; + conditions.isX3MaSwitchedToBearishOrdered = isX3MaSwitchedToBearishOrdered; + conditions.isX3MaSwitchedToBullishState = isX3MaSwitchedToBullishState; + conditions.isX3MaSwitchedToBearishState = isX3MaSwitchedToBearishState; + conditions.isX3MaSwitchedToNeuturalState = isX3MaSwitchedToNeuturalState; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121X3MAInputs mInputs; // Inputs ... + + // + // Buffers ... + double x3maFastBuffer[]; + double x3maMidBuffer[]; + double x3maSlowBuffer[]; + double x3maFastStateBuffer[]; + double x3maMidStateBuffer[]; + double x3maSlowStateBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // FAST ... + CopyBuffer( + mHandler, + X121_X3MA_FAST_LINE, + 0, + maxRequiredBars, + x3maFastBuffer + // + ); + + // + // FAST STATE ... + CopyBuffer( + mHandler, + X121_X3MA_FAST_STATE_LINE, + 0, + maxRequiredBars, + x3maFastStateBuffer + // + ); + + // + // MID ... + CopyBuffer( + mHandler, + X121_X3MA_MID_LINE, + 0, + maxRequiredBars, + x3maMidBuffer + // + ); + + // + // MID STATE ... + CopyBuffer( + mHandler, + X121_X3MA_MID_STATE_LINE, + 0, + maxRequiredBars, + x3maMidStateBuffer + // + ); + + // + // SLOW ... + CopyBuffer( + mHandler, + X121_X3MA_SLOW_LINE, + 0, + maxRequiredBars, + x3maSlowBuffer + // + ); + + // + // SLOW STATE ... + CopyBuffer( + mHandler, + X121_X3MA_SLOW_STATE_LINE, + 0, + maxRequiredBars, + x3maSlowStateBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + x3maFastBuffer, + maxAllowed // + ); + + // + CleanupArray( + x3maMidBuffer, + maxAllowed // + ); + + // + CleanupArray( + x3maSlowBuffer, + maxAllowed // + ); + + // + CleanupArray( + x3maFastStateBuffer, + maxAllowed // + ); + + // + CleanupArray( + x3maMidStateBuffer, + maxAllowed // + ); + + // + CleanupArray( + x3maSlowStateBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xatr.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xatr.helper.mq5 new file mode 100644 index 0000000..2c7b5c4 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xatr.helper.mq5 @@ -0,0 +1,1273 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XATRHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XATR_BUFFERS +{ + // + X121_ATR_UPPER_LINE = 0, + X121_ATR_LOWER_LINE = 1, + X121_ATR_LINE = 2, + X121_ATR_UPPER_RAW_LINE = 3, + X121_ATR_LOWER_RAW_LINE = 4, + X121_RSI_LINE = 5, +}; + +// +// Input Models ... +struct X121XATRInputs +{ + // + // Props ... + + // + // RSI ... + int rsiLength; // Length + double rsiOverSoldLevel; // Over Sold Level + double rsiOverBoughtLevel; // Over Bought Level + ENUM_APPLIED_PRICE rsiAppliedTo; // Applied To + + // + // ATR Detection ... + int atrLength; // Length + double atrMultiplier; // Multiplier + ENUM_APPLIED_PRICE atrUpperAppliedTo; // Upper Zone Applied To + ENUM_APPLIED_PRICE atrLowerAppliedTo; // Lower Zone Applied To + ENUM_X_MA_METHOD atrSmoothingMode; // Smoothing Method + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showATRUpper; // Show Upper Zone + bool showATRLower; // Show Lower Zone + + // + // Constructor(s) ... + X121XATRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + // RSI ... + rsiLength = 0; + rsiOverSoldLevel = 0; + rsiOverBoughtLevel = 0; + rsiAppliedTo = PRICE_CLOSE; + + // + // ATR ... + atrLength = 0; // Length + atrMultiplier = 0; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_NONE; // Smoothing Method + + // + startCalculationForLastBars = 0; + + // + showATRUpper = false; // Show Upper Zone + showATRLower = false; // Show Lower Zone + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + // RSI ... + rsiLength = 14; + rsiOverSoldLevel = 30; + rsiOverBoughtLevel = 70; + rsiAppliedTo = PRICE_CLOSE; + + // + // ATR ... + atrLength = 14; // Length + atrMultiplier = 1; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + + // + startCalculationForLastBars = 1500; + showATRUpper = true; // Show Upper Zone + showATRLower = true; // Show Lower Zone + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + atrLength > 0 && + rsiLength > 0 && + atrMultiplier > 0 && + rsiOverSoldLevel > 0 && + rsiOverBoughtLevel > 0 && + startCalculationForLastBars > 0 && + rsiOverSoldLevel < rsiOverBoughtLevel + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(atrLength, rsiLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XATRConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double rsiBuffer[]; + double atrBuffer[]; + + // + // Conditions ... + + // + // RSI ... + + // + bool isRsiOverBought; + bool isRsiCrossedOverOverBought; + bool isRsiCrossedUnderOverBought; + + // + bool isRsiOverSold; + bool isRsiCrossedUnderOverSold; + bool isRsiCrossedOverOverSold; + + // + // ATR ... + + // + bool isClosedOverAtrUpper; + bool isClosedOverAtrLower; + + // + bool isClosedUnderAtrUpper; + bool isClosedUnderAtrLower; + + // + bool isRejectedUpAtrUpper; + bool isRejectedDownAtrUpper; + + // + bool isRejectedUpAtrLower; + bool isRejectedDownAtrLower; + + // + bool isBreakedUpAtrUpper; + bool isBreakedDownAtrUpper; + + // + bool isBreakedUpAtrLower; + bool isBreakedDownAtrLower; + + // + // bool isCloseLower + + // + // Constructor ... + X121XATRConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(rsiBuffer); + Clean(atrBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + + // + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + + // + // Conditions ... + + // + // RSI ... + + // + isRsiOverBought = false; + isRsiCrossedOverOverBought = false; + isRsiCrossedUnderOverBought = false; + + // + isRsiOverSold = false; + isRsiCrossedUnderOverSold = false; + isRsiCrossedOverOverSold = false; + + // + // ATR ... + + // + isClosedOverAtrUpper = false; + isClosedOverAtrLower = false; + + // + isClosedUnderAtrUpper = false; + isClosedUnderAtrLower = false; + + // + isRejectedUpAtrUpper = false; + isRejectedDownAtrUpper = false; + + // + isRejectedUpAtrLower = false; + isRejectedDownAtrLower = false; + + // + isBreakedUpAtrUpper = false; + isBreakedDownAtrUpper = false; + + // + isBreakedUpAtrLower = false; + isBreakedDownAtrLower = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + // RSI ... + ToString("isRsiOverBought", isRsiOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverBought", isRsiCrossedOverOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverBought", isRsiCrossedUnderOverBought, ignoreFalseConditions, separator) + + ToString("isRsiOverSold", isRsiOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverSold", isRsiCrossedUnderOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverSold", isRsiCrossedOverOverSold, ignoreFalseConditions, separator) + + // + // ATR ... + ToString("isClosedOverAtrUpper", isClosedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedOverAtrLower", isClosedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrUpper", isClosedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrLower", isClosedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrUpper", isRejectedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrUpper", isRejectedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrLower", isRejectedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrLower", isRejectedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrUpper", isBreakedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrUpper", isBreakedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrLower", isBreakedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrLower", isBreakedDownAtrLower, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XATRHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XATRHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XATRHelper() + { + // + Clean(rsiBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(atrBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + + // + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XATRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xatr", + // + // Inputs ... + // + // Market ... + "", + // + // RSI Detection ... + "", + mInputs.rsiLength, + mInputs.rsiAppliedTo, + // + // ATR Detection ... + "", + mInputs.atrLength, + mInputs.atrMultiplier, + mInputs.atrUpperAppliedTo, + mInputs.atrLowerAppliedTo, + mInputs.atrSmoothingMode, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + mInputs.showATRUpper, + mInputs.showATRLower + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XATRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XATRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // RSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(rsiBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return rsiBuffer[barIndex]; + } + + // + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperBuffer[barIndex]; + } + + // + int CopyATRUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRUpperRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperRawBuffer[barIndex]; + } + + // + int CopyATRUpperRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperRawBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerBuffer[barIndex]; + } + + // + int CopyATRLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRLowerRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerRawBuffer[barIndex]; + } + + // + int CopyATRLowerRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerRawBuffer, + buffer, + forceClean + // + ); + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XATRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyRSI( + zIndex, + loopback, + conditions.rsiBuffer // + ); + + // + CopyATR( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopyATRUpper( + zIndex, + loopback, + conditions.atrUpperBuffer // + ); + + // + CopyATRUpperRaw( + zIndex, + loopback, + conditions.atrUpperRawBuffer // + ); + + // + CopyATRLower( + zIndex, + loopback, + conditions.atrLowerBuffer // + ); + + // + CopyATRLowerRaw( + zIndex, + loopback, + conditions.atrLowerRawBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // RSI ... + + // + bool isRsiOverBought = conditions.rsiBuffer[cIDX] > mInputs.rsiOverBoughtLevel; + bool isRsiOverBoughtPrev = conditions.rsiBuffer[pIDX] > mInputs.rsiOverBoughtLevel; + + // + bool isRsiCrossedOverOverBought = isRsiOverBought && + !isRsiOverBoughtPrev; + bool isRsiCrossedUnderOverBought = !isRsiOverBought && + isRsiOverBoughtPrev; + + // + bool isRsiOverSold = conditions.rsiBuffer[cIDX] < mInputs.rsiOverSoldLevel; + bool isRsiOverSoldPrev = conditions.rsiBuffer[pIDX] < mInputs.rsiOverSoldLevel; + + // + bool isRsiCrossedUnderOverSold = isRsiOverSold && + !isRsiOverSoldPrev; + bool isRsiCrossedOverOverSold = !isRsiOverSold && + isRsiOverSoldPrev; + + // + // ATR ... + + // + bool isClosedOverAtrUpper = cBar.close > conditions.atrUpperBuffer[cIDX]; + bool isClosedOverAtrLower = cBar.close > conditions.atrLowerBuffer[cIDX]; + + // + bool isClosedUnderAtrUpper = cBar.close < conditions.atrUpperBuffer[cIDX]; + bool isClosedUnderAtrLower = cBar.close < conditions.atrLowerBuffer[cIDX]; + + // + bool isRejectedUpAtrUpper = IsBarReject( + atrUpperBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDownAtrUpper = IsBarReject( + atrUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpAtrLower = IsBarReject( + atrLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + ; + bool isRejectedDownAtrLower = IsBarReject( + atrLowerBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + ; + + // + bool isBreakedUpAtrUpper = IsBarBreak( + atrUpperBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownAtrUpper = IsBarBreak( + atrUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpAtrLower = IsBarBreak( + atrLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownAtrLower = IsBarBreak( + atrLowerBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + conditions.isRsiOverSold = isRsiOverSold; + conditions.isRsiOverBought = isRsiOverBought; + conditions.isRejectedUpAtrUpper = isRejectedUpAtrUpper; + conditions.isRejectedUpAtrLower = isRejectedUpAtrLower; + conditions.isBreakedUpAtrUpper = isBreakedUpAtrUpper; + conditions.isBreakedUpAtrLower = isBreakedUpAtrLower; + conditions.isRejectedDownAtrUpper = isRejectedDownAtrUpper; + conditions.isRejectedDownAtrLower = isRejectedDownAtrLower; + conditions.isClosedOverAtrUpper = isClosedOverAtrUpper; + conditions.isClosedOverAtrLower = isClosedOverAtrLower; + conditions.isBreakedDownAtrUpper = isBreakedDownAtrUpper; + conditions.isBreakedDownAtrLower = isBreakedDownAtrLower; + conditions.isClosedUnderAtrUpper = isClosedUnderAtrUpper; + conditions.isClosedUnderAtrLower = isClosedUnderAtrLower; + conditions.isRsiCrossedOverOverSold = isRsiCrossedOverOverSold; + conditions.isRsiCrossedUnderOverSold = isRsiCrossedUnderOverSold; + conditions.isRsiCrossedOverOverBought = isRsiCrossedOverOverBought; + conditions.isRsiCrossedUnderOverBought = isRsiCrossedUnderOverBought; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XATRInputs mInputs; // Inputs ... + + // + // Buffers ... + double rsiBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // RSI ... + CopyBuffer( + mHandler, + X121_RSI_LINE, + 0, + maxRequiredBars, + rsiBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_LINE, + 0, + maxRequiredBars, + atrUpperBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_LINE, + 0, + maxRequiredBars, + atrLowerBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LINE, + 0, + maxRequiredBars, + atrBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_RAW_LINE, + 0, + maxRequiredBars, + atrUpperRawBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_RAW_LINE, + 0, + maxRequiredBars, + atrLowerRawBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + rsiBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrUpperBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrLowerBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrUpperRawBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrLowerRawBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xcc.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xcc.helper.mq5 new file mode 100644 index 0000000..bcef12e --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xcc.helper.mq5 @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCCHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCCInputs +{ + // + // Props ... + + // + // Chart Style ... + ENUM_CHART_MODE mode; // Mode + color upColor; // Up Color + color downColor; // Down Color + color lineColor; // Line mode and Doji candlestick Color + color bearishColor; // Bullish Color + color bullishColor; // Bearish Color + color volumesColor; // Volumes Color + + // + // Presentation ... + bool showCandles; // Show Candles + + // + // Constructor(s) ... + X121XCCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + mode = CHART_CANDLES; + + // + upColor = CLR_NONE; + downColor = CLR_NONE; + lineColor = CLR_NONE; + bearishColor = CLR_NONE; + bullishColor = CLR_NONE; + volumesColor = CLR_NONE; + + // + showCandles = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + mode = CHART_CANDLES; + + // + upColor = clrLime; + downColor = clrRed; + lineColor = clrLime; + bearishColor = clrRed; + bullishColor = clrLime; + volumesColor = clrGreen; + // + showCandles = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCCHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCCHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCCHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xcc", + // + // Inputs ... + // + // Chart Style ... + "", + mInputs.mode, // Mode + mInputs.upColor, // Up Color + mInputs.downColor, // Down Color + mInputs.lineColor, // Line mode and Doji candlestick Color + mInputs.bearishColor, // Bullish Color + mInputs.bullishColor, // Bearish Color + mInputs.volumesColor, // Volumes Color + // + // Presentation ... + "", + mInputs.showCandles // Show Candles + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCCInputs mInputs; // Inputs ... +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xche.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xche.helper.mq5 new file mode 100644 index 0000000..7f7cecd --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xche.helper.mq5 @@ -0,0 +1,1387 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XCHEHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XCHE_BUFFERS +{ + // + X121_XCHE_LE_1_LINE = 0, + X121_XCHE_SE_1_LINE = 1, + X121_XCHE_LE_2_LINE = 2, + X121_XCHE_SE_2_LINE = 3, + X121_XCHE_LE_1_S_LINE = 4, + X121_XCHE_SE_1_S_LINE = 5, + X121_XCHE_LE_2_S_LINE = 6, + X121_XCHE_SE_2_S_LINE = 7, +}; + +// +// Input Models ... +struct X121XCHEInputs +{ + // + // Props ... + + int cheLength; // Length + int cheLoopback; // Loopback + double cheMultiplier1; // 1st Multiplier + double cheMultiplier2; // 2nd Multiplier + ENUM_APPLIED_PRICE cheUpperAppliedTo; // Upper Zone Applied to + ENUM_APPLIED_PRICE cheLowerAppliedTo; // Lower Zone Applied to + + // + int cheArrowCode; // CHE Arrow Code + + // + bool showLE1; // Show 1st Long Exit + bool showSE1; // Show 1st Short Exit + bool showLE2; // Show 2st Long Exit + bool showSE2; // Show 2st Short Exit + + // + // Constructor(s) ... + X121XCHEInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + cheLength = 0; + cheLoopback = 0; + cheMultiplier1 = 0; + cheMultiplier2 = 0; + cheUpperAppliedTo = PRICE_HIGH; + cheLowerAppliedTo = PRICE_LOW; + + // + cheArrowCode = 0; + + // + showLE1 = false; + showSE1 = false; + showLE2 = false; + showSE2 = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + cheLength = 35; + cheLoopback = 26; + cheMultiplier1 = 3.0; + cheMultiplier2 = 3.5; + cheUpperAppliedTo = PRICE_HIGH; + cheLowerAppliedTo = PRICE_LOW; + + // + cheArrowCode = 159; + + // + showLE1 = true; + showSE1 = true; + showLE2 = true; + showSE2 = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = true; + + // + result = + cheLength >= 9 && + cheLoopback >= 0; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(cheLength, cheLoopback); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XCHEConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + + // + // Conditions ... + + // + bool isChe1Bullish; + bool isChe1Bearish; + + // + bool isChe1SwitchedToBullish; + bool isChe1SwitchedToBearish; + + // + bool isChe2Bullish; + bool isChe2Bearish; + + // + bool isChe2SwitchedToBullish; + bool isChe2SwitchedToBearish; + + // + bool isCheBullish; + bool isCheBearish; + + // + bool isCheSwitchedToBullish; + bool isCheSwitchedToBearish; + + // + bool isClosedOverCheMin; + bool isClosedOverCheMax; + + // + bool isClosedUnderCheMin; + bool isClosedUnderCheMax; + + // + // Constructor ... + X121XCHEConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(le1Buffer); + Clean(se1Buffer); + Clean(le2Buffer); + Clean(se2Buffer); + Clean(le1StartBuffer); + Clean(se1StartBuffer); + Clean(le2StartBuffer); + Clean(se2StartBuffer); + + // + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + + // + // Conditions ... + + // + isChe1Bullish = false; + isChe1Bearish = false; + + // + isChe1SwitchedToBullish = false; + isChe1SwitchedToBearish = false; + + // + isChe2Bullish = false; + isChe2Bearish = false; + + // + isChe2SwitchedToBullish = false; + isChe2SwitchedToBearish = false; + + // + isCheBullish = false; + isCheBearish = false; + + // + isCheSwitchedToBullish = false; + isCheSwitchedToBearish = false; + + // + isClosedOverCheMin = false; + isClosedOverCheMax = false; + + // + isClosedUnderCheMin = false; + isClosedUnderCheMax = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isChe1Bullish", isChe1Bullish, ignoreFalseConditions, separator) + + ToString("isChe1Bearish", isChe1Bearish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBullish", isChe1SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBearish", isChe1SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isChe2Bullish", isChe2Bullish, ignoreFalseConditions, separator) + + ToString("isChe2Bearish", isChe2Bearish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBullish", isChe2SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBearish", isChe2SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isCheBullish", isCheBullish, ignoreFalseConditions, separator) + + ToString("isCheBearish", isCheBearish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBullish", isCheSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBearish", isCheSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMin", isClosedOverCheMin, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMax", isClosedOverCheMax, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMin", isClosedUnderCheMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMax", isClosedUnderCheMax, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XCHEHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCHEHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCHEHelper() + { + // + mInputs.Clean(); + + // + Clean(le1Buffer); + Clean(se1Buffer); + Clean(le2Buffer); + Clean(se2Buffer); + Clean(le1StartBuffer); + Clean(se1StartBuffer); + Clean(le2StartBuffer); + Clean(se2StartBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCHEInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + mInputs.cheLength, + mInputs.cheLoopback, + mInputs.cheMultiplier1, + mInputs.cheMultiplier2, + mInputs.cheUpperAppliedTo, + mInputs.cheLowerAppliedTo, + // + // Presentation ... + "", + mInputs.cheArrowCode, + mInputs.showLE1, + mInputs.showSE1, + mInputs.showLE2, + mInputs.showSE2 + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCHEInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCHEInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + double GetLE1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le1Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le1Buffer[barIndex]; + } + + // + int CopyLE1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLE1Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le1StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le1StartBuffer[barIndex]; + } + + // + int CopyLE1Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le1StartBuffer, + buffer, + forceClean + // + ); + } + + // + double GetLE2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le2Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le2Buffer[barIndex]; + } + + // + int CopyLE2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le2Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLE2Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le2StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le2StartBuffer[barIndex]; + } + + // + int CopyLE2Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le2StartBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSE1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se1Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se1Buffer[barIndex]; + } + + // + int CopySE1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se1Buffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE1Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se1StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se1StartBuffer[barIndex]; + } + + // + int CopySE1Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se1StartBuffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se2Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se2Buffer[barIndex]; + } + + // + int CopySE2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se2Buffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE2Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se2StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se2StartBuffer[barIndex]; + } + + // + int CopySE2Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se2StartBuffer, + buffer, + forceCsean + // + ); + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XCHEConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyLE1( + zIndex, + loopback, + conditions.le1Buffer // + ); + + // + CopySE1( + zIndex, + loopback, + conditions.se1Buffer // + ); + + // + CopyLE2( + zIndex, + loopback, + conditions.le2Buffer // + ); + + // + CopySE2( + zIndex, + loopback, + conditions.se2Buffer // + ); + + // + CopyLE1Start( + zIndex, + loopback, + conditions.le1StartBuffer // + ); + + // + CopySE1Start( + zIndex, + loopback, + conditions.se1StartBuffer // + ); + + // + CopyLE2Start( + zIndex, + loopback, + conditions.le2StartBuffer // + ); + + // + CopySE2Start( + zIndex, + loopback, + conditions.se2StartBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isChe1Bullish = le1Buffer[cIDX] != EMPTY_VALUE && + se1Buffer[cIDX] == EMPTY_VALUE; + bool isChe1BullishPrev = le1Buffer[cIDX] != EMPTY_VALUE && + se1Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe1Bearish = se1Buffer[cIDX] != EMPTY_VALUE && + le1Buffer[cIDX] == EMPTY_VALUE; + bool isChe1BearishPrev = se1Buffer[pIDX] != EMPTY_VALUE && + le1Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe1SwitchedToBullish = isChe1Bullish && + !isChe1BullishPrev; + bool isChe1SwitchedToBearish = isChe1Bearish && + !isChe1BearishPrev; + + // + bool isChe2Bullish = le2Buffer[cIDX] != EMPTY_VALUE && + se2Buffer[cIDX] == EMPTY_VALUE; + bool isChe2BullishPrev = le2Buffer[pIDX] != EMPTY_VALUE && + se2Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe2Bearish = se2Buffer[cIDX] != EMPTY_VALUE && + le2Buffer[cIDX] == EMPTY_VALUE; + bool isChe2BearishPrev = se2Buffer[pIDX] != EMPTY_VALUE && + le2Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe2SwitchedToBullish = isChe2Bullish && + !isChe2BullishPrev; + bool isChe2SwitchedToBearish = isChe2Bearish && + !isChe2BearishPrev; + + // + bool isCheBullish = isChe1Bullish && + isChe2Bullish; + bool isCheBullishPrev = isChe1BullishPrev && + isChe2BullishPrev; + + // + bool isCheBearish = isChe1Bearish && + isChe2Bearish; + bool isCheBearishPrev = isChe1BearishPrev && + isChe2BearishPrev; + + // + bool isCheSwitchedToBullish = isCheBullish && + !isCheBullishPrev; + bool isCheSwitchedToBearish = isCheBearish && + !isCheBearishPrev; + + // + double ches[]; + double prevCheLE1 = le1Buffer[pIDX]; + double prevCheLE2 = le2Buffer[pIDX]; + double prevCheSE1 = se1Buffer[pIDX]; + double prevCheSE2 = se2Buffer[pIDX]; + if (prevCheLE1 != EMPTY_VALUE) + { + // + Add( + prevCheLE1, + ches // + ); + } + if (prevCheLE2 != EMPTY_VALUE) + { + // + Add( + prevCheLE2, + ches // + ); + } + if (prevCheSE1 != EMPTY_VALUE) + { + // + Add( + prevCheSE1, + ches // + ); + } + if (prevCheSE2 != EMPTY_VALUE) + { + // + Add( + prevCheSE2, + ches // + ); + } + + // + double cheMin = GetMin(ches); + double cheMax = GetMax(ches); + + // + bool isClosedOverCheMin = cBar.close > cheMin; + bool isClosedOverCheMax = cBar.close > cheMax; + bool isClosedUnderCheMin = cBar.close < cheMin; + bool isClosedUnderCheMax = cBar.close < cheMax; + + // + conditions.isChe1Bullish = isChe1Bullish; + conditions.isChe1Bearish = isChe1Bearish; + conditions.isChe1SwitchedToBullish = isChe1SwitchedToBullish; + conditions.isChe1SwitchedToBearish = isChe1SwitchedToBearish; + conditions.isChe2Bullish = isChe2Bullish; + conditions.isChe2Bearish = isChe2Bearish; + conditions.isChe2SwitchedToBullish = isChe2SwitchedToBullish; + conditions.isChe2SwitchedToBearish = isChe2SwitchedToBearish; + conditions.isCheBullish = isCheBullish; + conditions.isCheBearish = isCheBearish; + conditions.isCheSwitchedToBullish = isCheSwitchedToBullish; + conditions.isCheSwitchedToBearish = isCheSwitchedToBearish; + conditions.isClosedOverCheMin = isClosedOverCheMin; + conditions.isClosedOverCheMax = isClosedOverCheMax; + conditions.isClosedUnderCheMin = isClosedUnderCheMin; + conditions.isClosedUnderCheMax = isClosedUnderCheMax; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCHEInputs mInputs; // Inputs ... + + // + // Buffers ... + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // LE1 Start ... + CopyBuffer( + mHandler, + X121_XCHE_LE_1_S_LINE, + 0, + maxRequiredBars, + le1StartBuffer // + ); + + // + // LE1 ... + CopyBuffer( + mHandler, + X121_XCHE_LE_1_LINE, + 0, + maxRequiredBars, + le1Buffer // + ); + + // + // LE2 Start ... + CopyBuffer( + mHandler, + X121_XCHE_LE_2_S_LINE, + 0, + maxRequiredBars, + le2StartBuffer // + ); + + // + // LE2 ... + CopyBuffer( + mHandler, + X121_XCHE_LE_2_LINE, + 0, + maxRequiredBars, + le2Buffer // + ); + + // + // SE1 Start ... + CopyBuffer( + mHandler, + X121_XCHE_SE_1_S_LINE, + 0, + maxRequiredBars, + se1StartBuffer // + ); + + // + // SE1 ... + CopyBuffer( + mHandler, + X121_XCHE_SE_1_LINE, + 0, + maxRequiredBars, + se1Buffer // + ); + + // + // SE2 Start ... + CopyBuffer( + mHandler, + X121_XCHE_SE_2_S_LINE, + 0, + maxRequiredBars, + se2StartBuffer // + ); + + // + // SE2 ... + CopyBuffer( + mHandler, + X121_XCHE_SE_2_LINE, + 0, + maxRequiredBars, + se2Buffer // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + le1Buffer, + maxAllowed // + ); + + // + CleanupArray( + se1Buffer, + maxAllowed // + ); + + // + CleanupArray( + le2Buffer, + maxAllowed // + ); + + // + CleanupArray( + se2Buffer, + maxAllowed // + ); + + // + CleanupArray( + le1StartBuffer, + maxAllowed // + ); + + // + CleanupArray( + se1StartBuffer, + maxAllowed // + ); + + // + CleanupArray( + le2StartBuffer, + maxAllowed // + ); + + // + CleanupArray( + se2StartBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xct.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xct.helper.mq5 new file mode 100644 index 0000000..c444481 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xct.helper.mq5 @@ -0,0 +1,234 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCTHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCTInputs +{ + // + // Props ... + + // + string font; // Font + int fontSize; // Font Size; + color clr; // Text Color + ENUM_BASE_CORNER corner; // Text Position + + // + // Presentation ... + bool showCandleTime; // Show Candle Time + + // + // Constructor(s) ... + X121XCTInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + font = NULL; + fontSize = 15; + clr = CLR_NONE; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + font = "Arial"; + fontSize = 15; + clr = clrYellow; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCTHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCTHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCTHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCTInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xct", + // + // Inputs ... + mInputs.fontSize, // Font Size ... + mInputs.font, // Font ... + mInputs.clr, // Text Color ... + mInputs.corner, // Text Position ... + // + // Presentation ... + "", + mInputs.showCandleTime // Show Candle Time + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCTInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCTInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCTInputs mInputs; // Inputs ... +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xdon.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xdon.helper.mq5 new file mode 100644 index 0000000..639df23 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xdon.helper.mq5 @@ -0,0 +1,1408 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XDONHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XDON_BUFFERS +{ + // + X121_XDON_OPEN_UPPER_LINE = 0, + X121_XDON_OPEN_LOWER_LINE = 1, + X121_XDON_HIGH_UPPER_LINE = 2, + X121_XDON_HIGH_LOWER_LINE = 3, + X121_XDON_LOW_UPPER_LINE = 4, + X121_XDON_LOW_LOWER_LINE = 5, + X121_XDON_CLOSE_UPPER_LINE = 6, + X121_XDON_CLOSE_LOWER_LINE = 7, +}; + +// +// Input Models ... +struct X121XDONInputs +{ + // + // Props ... + + // + int donchainLength; // Donchain Length + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showUpper; // Show Upper Band + bool showLower; // Show Lower Band + + // + bool showOpen; // Show Open + bool showHigh; // Show High + bool showClose; // Show Close + bool showLow; // Show Low + + // + // Constructor(s) ... + X121XDONInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + donchainLength = 0; + + // + startCalculationForLastBars = 0; + + // + showUpper = false; + showLower = false; + + // + showOpen = false; + showHigh = false; + showClose = false; + showLow = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + donchainLength = 40; + + // + startCalculationForLastBars = 1000; + + // + showUpper = true; + showLower = true; + + // + showOpen = true; + showHigh = true; + showClose = true; + showLow = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + donchainLength > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, donchainLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XDONConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + + // + // Conditions ... + + // + bool isRejectedDonOpenUpper; + bool isRejectedDonHighUpper; + bool isRejectedDonLowUpper; + bool isRejectedDonCloseUpper; + + // + bool isRejectedDonOpenLower; + bool isRejectedDonHighLower; + bool isRejectedDonLowLower; + bool isRejectedDonCloseLower; + + // + bool isBreakedDonOpenUpper; + bool isBreakedDonHighUpper; + bool isBreakedDonLowUpper; + bool isBreakedDonCloseUpper; + + // + bool isBreakedDonOpenLower; + bool isBreakedDonHighLower; + bool isBreakedDonLowLower; + bool isBreakedDonCloseLower; + + // + // Constructor ... + X121XDONConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + + // + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + + // + // Conditions ... + + // + isRejectedDonOpenUpper = false; + isRejectedDonHighUpper = false; + isRejectedDonLowUpper = false; + isRejectedDonCloseUpper = false; + + // + isRejectedDonOpenLower = false; + isRejectedDonHighLower = false; + isRejectedDonLowLower = false; + isRejectedDonCloseLower = false; + + // + isBreakedDonOpenUpper = false; + isBreakedDonHighUpper = false; + isBreakedDonLowUpper = false; + isBreakedDonCloseUpper = false; + + // + isBreakedDonOpenLower = false; + isBreakedDonHighLower = false; + isBreakedDonLowLower = false; + isBreakedDonCloseLower = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isRejectedDonOpenUpper", isRejectedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighUpper", isRejectedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowUpper", isRejectedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseUpper", isRejectedDonCloseUpper, ignoreFalseConditions, separator) + + // + ToString("isRejectedDonOpenLower", isRejectedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighLower", isRejectedDonHighLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowLower", isRejectedDonLowLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseLower", isRejectedDonCloseLower, ignoreFalseConditions, separator) + + // + ToString("isBreakedDonOpenUpper", isBreakedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighUpper", isBreakedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowUpper", isBreakedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseUpper", isBreakedDonCloseUpper, ignoreFalseConditions, separator) + + // + ToString("isBreakedDonOpenLower", isBreakedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighLower", isBreakedDonHighLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowLower", isBreakedDonLowLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseLower", isBreakedDonCloseLower, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XDONHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XDONHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XDONHelper() + { + // + mInputs.Clean(); + + // + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XDONInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xdon", + // + // Inputs ... + // + // Market ... + "", + mInputs.donchainLength, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + // + mInputs.showUpper, + mInputs.showLower, + // + mInputs.showOpen, + mInputs.showHigh, + mInputs.showClose, + mInputs.showLow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XDONInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XDONInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // OPEN ... + + // + // UPPER ... + + // + double GetDonOpenUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenUpperBuffer[barIndex]; + } + + // + int CopyDonOpenUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonOpenLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenLowerBuffer[barIndex]; + } + + // + int CopyDonOpenLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // CLOSE ... + + // + // UPPER ... + + // + double GetDonCloseUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseUpperBuffer[barIndex]; + } + + // + int CopyDonCloseUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonCloseLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseLowerBuffer[barIndex]; + } + + // + int CopyDonCloseLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // HIGH ... + + // + // UPPER ... + + // + double GetDonHighUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighUpperBuffer[barIndex]; + } + + // + int CopyDonHighUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonHighLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighLowerBuffer[barIndex]; + } + + // + int CopyDonHighLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // LOW ... + + // + // UPPER ... + + // + double GetDonLowUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowUpperBuffer[barIndex]; + } + + // + int CopyDonLowUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonLoweLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowLowerBuffer[barIndex]; + } + + // + int CopyDonLoweLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowLowerBuffer, + buffer, + forceClean + // + ); + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XDONConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyDonOpenUpper( + zIndex, + loopback, + conditions.donOpenUpperBuffer // + ); + + // + CopyDonOpenLower( + zIndex, + loopback, + conditions.donOpenLowerBuffer // + ); + + // + CopyDonCloseUpper( + zIndex, + loopback, + conditions.donCloseUpperBuffer // + ); + + // + CopyDonCloseLower( + zIndex, + loopback, + conditions.donCloseLowerBuffer // + ); + + // + CopyDonHighUpper( + zIndex, + loopback, + conditions.donHighUpperBuffer // + ); + + // + CopyDonHighLower( + zIndex, + loopback, + conditions.donHighLowerBuffer // + ); + + // + CopyDonLowUpper( + zIndex, + loopback, + conditions.donLowUpperBuffer // + ); + + // + CopyDonLoweLower( + zIndex, + loopback, + conditions.donLowLowerBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isRejectedDonOpenUpper = IsBarReject( + donOpenUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonHighUpper = IsBarReject( + donHighUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonLowUpper = IsBarReject( + donLowUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonCloseUpper = IsBarReject( + donCloseUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedDonOpenLower = IsBarReject( + donOpenLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonHighLower = IsBarReject( + donHighLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonLowLower = IsBarReject( + donLowLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonCloseLower = IsBarReject( + donCloseLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isBreakedDonOpenUpper = IsBarBreak( + donOpenUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonHighUpper = IsBarBreak( + donHighUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonLowUpper = IsBarBreak( + donLowUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonCloseUpper = IsBarBreak( + donCloseUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedDonOpenLower = IsBarBreak( + donOpenLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonHighLower = IsBarBreak( + donHighLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonLowLower = IsBarBreak( + donLowLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonCloseLower = IsBarBreak( + donCloseLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + conditions.isBreakedDonLowUpper = isBreakedDonLowUpper; + conditions.isBreakedDonLowLower = isBreakedDonLowLower; + conditions.isRejectedDonLowUpper = isRejectedDonLowUpper; + conditions.isRejectedDonLowLower = isRejectedDonLowLower; + conditions.isBreakedDonOpenUpper = isBreakedDonOpenUpper; + conditions.isBreakedDonHighUpper = isBreakedDonHighUpper; + conditions.isBreakedDonOpenLower = isBreakedDonOpenLower; + conditions.isBreakedDonHighLower = isBreakedDonHighLower; + conditions.isRejectedDonOpenUpper = isRejectedDonOpenUpper; + conditions.isRejectedDonOpenLower = isRejectedDonOpenLower; + conditions.isRejectedDonHighUpper = isRejectedDonHighUpper; + conditions.isRejectedDonHighLower = isRejectedDonHighLower; + conditions.isBreakedDonCloseUpper = isBreakedDonCloseUpper; + conditions.isBreakedDonCloseLower = isBreakedDonCloseLower; + conditions.isRejectedDonCloseUpper = isRejectedDonCloseUpper; + conditions.isRejectedDonCloseLower = isRejectedDonCloseLower; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XDONInputs mInputs; // Inputs ... + + // + // Buffers ... + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_OPEN_UPPER_LINE, + 0, + maxRequiredBars, + donOpenUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_OPEN_LOWER_LINE, + 0, + maxRequiredBars, + donOpenLowerBuffer + // + ); + + // + // CLOSE ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_CLOSE_UPPER_LINE, + 0, + maxRequiredBars, + donCloseUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_CLOSE_LOWER_LINE, + 0, + maxRequiredBars, + donCloseLowerBuffer + // + ); + + // + // HIGH ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_HIGH_UPPER_LINE, + 0, + maxRequiredBars, + donHighUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_HIGH_LOWER_LINE, + 0, + maxRequiredBars, + donHighLowerBuffer + // + ); + + // + // LOW ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_LOW_UPPER_LINE, + 0, + maxRequiredBars, + donLowUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_LOW_LOWER_LINE, + 0, + maxRequiredBars, + donLowLowerBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + donOpenUpperBuffer, + maxAllowed // + ); + + // + CleanupArray( + donOpenLowerBuffer, + maxAllowed // + ); + + // + CleanupArray( + donHighUpperBuffer, + maxAllowed // + ); + + // + CleanupArray( + donHighLowerBuffer, + maxAllowed // + ); + + // + CleanupArray( + donLowUpperBuffer, + maxAllowed // + ); + + // + CleanupArray( + donLowLowerBuffer, + maxAllowed // + ); + + // + CleanupArray( + donCloseUpperBuffer, + maxAllowed // + ); + + // + CleanupArray( + donCloseLowerBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xhk.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xhk.helper.mq5 new file mode 100644 index 0000000..0a4e89a --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xhk.helper.mq5 @@ -0,0 +1,1524 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XHKHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XHK_BUFFERS +{ + // + X121_XHK_RAW_OPEN_LINE = 0, + X121_XHK_RAW_HIGH_LINE = 1, + X121_XHK_RAW_LOW_LINE = 2, + X121_XHK_RAW_CLOSE_LINE = 3, + // + X121_XHK_SM_OPEN_LINE = 5, + X121_XHK_SM_HIGH_LINE = 6, + X121_XHK_SM_LOW_LINE = 7, + X121_XHK_SM_CLOSE_LINE = 8, +}; + +// +// Input Models ... +struct X121XHKInputs +{ + // + // Props ... + int xhkSmoothingLength; // Length + ENUM_X_MA_METHOD xhkSmoothingMode; // Smoothing Method + bool xhkIgnoreSmoothingShadows; // Ignore Smoothed Bar Shadows + int startCalculationForLastBars; // Calculate Last n Bars + bool drawRawXHKCandles; // Draw Raw Candle + bool drawSmoothedXHKCandles; // Draw Smoothed Candle + + // + // Constructor(s) ... + X121XHKInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + xhkSmoothingLength = 0; + xhkSmoothingMode = X_MA_MODE_NONE; + xhkIgnoreSmoothingShadows = false; + startCalculationForLastBars = 1500; + drawRawXHKCandles = false; + drawSmoothedXHKCandles = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + xhkSmoothingLength = 14; + xhkSmoothingMode = X_MA_MODE_EMA; + xhkIgnoreSmoothingShadows = false; + startCalculationForLastBars = 1500; + drawRawXHKCandles = true; + drawSmoothedXHKCandles = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, xhkSmoothingLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XHKConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + + // + double xhkRawOpenBuffer[]; + double xhkRawHighBuffer[]; + double xhkRawLowBuffer[]; + double xhkRawCloseBuffer[]; + + // + double xhkSMOpenBuffer[]; + double xhkSMHighBuffer[]; + double xhkSMLowBuffer[]; + double xhkSMCloseBuffer[]; + + // + // Conditions ... + + // + bool isSMHKBullish; + bool isRawHKBullish; + bool isSMHKSwitchedToBullish; + bool isRawHKSwitchedToBullish; + + // + bool isSMHKBearish; + bool isRawHKBearish; + bool isSMHKSwitchedToBearish; + bool isRawHKSwitchedToBearish; + + // + bool isClosedOverSMHK; + bool isClosedUnderSMHK; + bool isClosedOverRawHK; + bool isClosedUnderRawHK; + + // + bool isRawHKClosedOverSMHK; + bool isRawHKClosedUnderSMHK; + + // + bool isBreakedUpSMHK; + bool isBreakedUpRawHK; + bool isRejectedUpSMHK; + bool isRejectedUpRawHK; + bool isRawHKBreakedUpSMHK; + + // + bool isBreakedDownSMHK; + bool isBreakedDownRawHK; + bool isRejectedDownSMHK; + bool isRejectedDownRawHK; + bool isRawHKBreakedDownSMHK; + + // + // Constructor ... + X121XHKConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(xhkRawOpenBuffer); + Clean(xhkRawHighBuffer); + Clean(xhkRawLowBuffer); + Clean(xhkRawCloseBuffer); + Clean(xhkSMOpenBuffer); + Clean(xhkSMHighBuffer); + Clean(xhkSMLowBuffer); + Clean(xhkSMCloseBuffer); + + // + ArraySetAsSeries(xhkRawOpenBuffer, true); + ArraySetAsSeries(xhkRawHighBuffer, true); + ArraySetAsSeries(xhkRawLowBuffer, true); + ArraySetAsSeries(xhkRawCloseBuffer, true); + ArraySetAsSeries(xhkSMOpenBuffer, true); + ArraySetAsSeries(xhkSMHighBuffer, true); + ArraySetAsSeries(xhkSMLowBuffer, true); + ArraySetAsSeries(xhkSMCloseBuffer, true); + + // + // Conditions ... + + // + isSMHKBullish = false; + isRawHKBullish = false; + isSMHKSwitchedToBullish = false; + isRawHKSwitchedToBullish = false; + + // + isSMHKBearish = false; + isRawHKBearish = false; + isSMHKSwitchedToBearish = false; + isRawHKSwitchedToBearish = false; + + // + isClosedOverSMHK = false; + isClosedUnderSMHK = false; + isClosedOverRawHK = false; + isClosedUnderRawHK = false; + + // + isRawHKClosedOverSMHK = false; + isRawHKClosedUnderSMHK = false; + + // + isBreakedUpSMHK = false; + isBreakedUpRawHK = false; + isRejectedUpSMHK = false; + isRejectedUpRawHK = false; + isRawHKBreakedUpSMHK = false; + + // + isBreakedDownSMHK = false; + isBreakedDownRawHK = false; + isRejectedDownSMHK = false; + isRejectedDownRawHK = false; + isRawHKBreakedDownSMHK = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isSMHKBullish", isSMHKBullish, ignoreFalseConditions, separator) + + ToString("isRawHKBullish", isRawHKBullish, ignoreFalseConditions, separator) + + ToString("isSMHKSwitchedToBullish", isSMHKSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isRawHKSwitchedToBullish", isRawHKSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSMHKBearish", isSMHKBearish, ignoreFalseConditions, separator) + + ToString("isRawHKBearish", isRawHKBearish, ignoreFalseConditions, separator) + + ToString("isSMHKSwitchedToBearish", isSMHKSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isRawHKSwitchedToBearish", isRawHKSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isClosedOverSMHK", isClosedOverSMHK, ignoreFalseConditions, separator) + + ToString("isClosedUnderSMHK", isClosedUnderSMHK, ignoreFalseConditions, separator) + + ToString("isClosedOverRawHK", isClosedOverRawHK, ignoreFalseConditions, separator) + + ToString("isClosedUnderRawHK", isClosedUnderRawHK, ignoreFalseConditions, separator) + + ToString("isRawHKClosedOverSMHK", isRawHKClosedOverSMHK, ignoreFalseConditions, separator) + + ToString("isRawHKClosedUnderSMHK", isRawHKClosedUnderSMHK, ignoreFalseConditions, separator) + + ToString("isBreakedUpSMHK", isBreakedUpSMHK, ignoreFalseConditions, separator) + + ToString("isBreakedUpRawHK", isBreakedUpRawHK, ignoreFalseConditions, separator) + + ToString("isRejectedUpSMHK", isRejectedUpSMHK, ignoreFalseConditions, separator) + + ToString("isRejectedUpRawHK", isRejectedUpRawHK, ignoreFalseConditions, separator) + + ToString("isRawHKBreakedUpSMHK", isRawHKBreakedUpSMHK, ignoreFalseConditions, separator) + + ToString("isBreakedDownSMHK", isBreakedDownSMHK, ignoreFalseConditions, separator) + + ToString("isBreakedDownRawHK", isBreakedDownRawHK, ignoreFalseConditions, separator) + + ToString("isRejectedDownSMHK", isRejectedDownSMHK, ignoreFalseConditions, separator) + + ToString("isRejectedDownRawHK", isRejectedDownRawHK, ignoreFalseConditions, separator) + + ToString("isRawHKBreakedDownSMHK", isRawHKBreakedDownSMHK, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XHKHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XHKHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XHKHelper() + { + // + Clean(xhkRawOpenBuffer); + Clean(xhkRawHighBuffer); + Clean(xhkRawLowBuffer); + Clean(xhkRawCloseBuffer); + Clean(xhkSMOpenBuffer); + Clean(xhkSMHighBuffer); + Clean(xhkSMLowBuffer); + Clean(xhkSMCloseBuffer); + + // + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XHKInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(xhkRawOpenBuffer, true); + ArraySetAsSeries(xhkRawHighBuffer, true); + ArraySetAsSeries(xhkRawLowBuffer, true); + ArraySetAsSeries(xhkRawCloseBuffer, true); + ArraySetAsSeries(xhkSMOpenBuffer, true); + ArraySetAsSeries(xhkSMHighBuffer, true); + ArraySetAsSeries(xhkSMLowBuffer, true); + ArraySetAsSeries(xhkSMCloseBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xhk", + // + // Inputs ... + // + // Market ... + "", + mInputs.xhkSmoothingLength, + mInputs.xhkSmoothingMode, + mInputs.xhkIgnoreSmoothingShadows, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + mInputs.drawRawXHKCandles, + mInputs.drawSmoothedXHKCandles + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XHKInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XHKInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + double GetRawHKOpen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkRawOpenBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkRawOpenBuffer[barIndex]; + } + + // + int CopyRawHKOpen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkRawOpenBuffer, + buffer, + forceClean + // + ); + } + + // + double GetRawHKHigh( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkRawHighBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkRawHighBuffer[barIndex]; + } + + // + int CopyRawHKHigh( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkRawHighBuffer, + buffer, + forceClean + // + ); + } + + // + double GetRawHKLow( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkRawLowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkRawLowBuffer[barIndex]; + } + + // + int CopyRawHKLow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkRawLowBuffer, + buffer, + forceClean + // + ); + } + + // + double GetRawHKClose( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkRawCloseBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkRawCloseBuffer[barIndex]; + } + + // + int CopyRawHKClose( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkRawCloseBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSMHKOpen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkSMOpenBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkSMOpenBuffer[barIndex]; + } + + // + int CopySMHKOpen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkSMOpenBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSMHKHigh( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkSMHighBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkSMHighBuffer[barIndex]; + } + + // + int CopySMHKHigh( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkSMHighBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSMHKLow( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkSMLowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkSMLowBuffer[barIndex]; + } + + // + int CopySMHKLow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkSMLowBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSMHKClose( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(xhkSMCloseBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return xhkSMCloseBuffer[barIndex]; + } + + // + int CopySMHKClose( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + xhkSMCloseBuffer, + buffer, + forceClean + // + ); + } + + // + bool GetRawHKAsXOHCL( + int barIndex, // Bar Index + XOHCL &bar // Bar Result + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = bar.Init( + GetSymbol(), + GetPeriod(), + barIndex // + ); + if (!result) + { + return result; + } + + // + bar.open = xhkRawOpenBuffer[barIndex]; + bar.high = xhkRawHighBuffer[barIndex]; + bar.low = xhkRawLowBuffer[barIndex]; + bar.close = xhkRawCloseBuffer[barIndex]; + + // + return result; + } + + // + bool GetSMHKAsXOHCL( + int barIndex, // Bar Index + XOHCL &bar // Bar Result + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = bar.Init( + GetSymbol(), + GetPeriod(), + barIndex // + ); + if (!result) + { + return result; + } + + // + bar.open = xhkSMOpenBuffer[barIndex]; + bar.high = xhkSMHighBuffer[barIndex]; + bar.low = xhkSMLowBuffer[barIndex]; + bar.close = xhkSMCloseBuffer[barIndex]; + + // + return result; + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XHKConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyRawHKOpen( + zIndex, + loopback, + conditions.xhkRawOpenBuffer // + ); + + // + CopyRawHKHigh( + zIndex, + loopback, + conditions.xhkRawHighBuffer // + ); + + // + CopyRawHKLow( + zIndex, + loopback, + conditions.xhkRawLowBuffer // + ); + + // + CopyRawHKClose( + zIndex, + loopback, + conditions.xhkRawCloseBuffer // + ); + + // + CopySMHKOpen( + zIndex, + loopback, + conditions.xhkSMOpenBuffer // + ); + + // + CopySMHKHigh( + zIndex, + loopback, + conditions.xhkSMHighBuffer // + ); + + // + CopySMHKLow( + zIndex, + loopback, + conditions.xhkSMLowBuffer // + ); + + // + CopySMHKClose( + zIndex, + loopback, + conditions.xhkSMCloseBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + double smHKLow = conditions.xhkSMLowBuffer[cIDX]; + double smHKHigh = conditions.xhkSMHighBuffer[cIDX]; + double smHKOpen = conditions.xhkSMOpenBuffer[cIDX]; + double smHKClose = conditions.xhkSMCloseBuffer[cIDX]; + + // + double smHKLowPrev = conditions.xhkSMLowBuffer[pIDX]; + double smHKHighPrev = conditions.xhkSMHighBuffer[pIDX]; + double smHKOpenPrev = conditions.xhkSMOpenBuffer[pIDX]; + double smHKClosePrev = conditions.xhkSMCloseBuffer[pIDX]; + + // + double rawHKLow = conditions.xhkRawLowBuffer[cIDX]; + double rawHKHigh = conditions.xhkRawHighBuffer[cIDX]; + double rawHKOpen = conditions.xhkRawOpenBuffer[cIDX]; + double rawHKClose = conditions.xhkRawCloseBuffer[cIDX]; + + // + double rawHKLowPrev = conditions.xhkRawLowBuffer[pIDX]; + double rawHKHighPrev = conditions.xhkRawHighBuffer[pIDX]; + double rawHKOpenPrev = conditions.xhkRawOpenBuffer[pIDX]; + double rawHKClosePrev = conditions.xhkRawCloseBuffer[pIDX]; + + // + double smHKUp = MathMax(smHKOpen, smHKClose); + double smHKUpPrev = MathMax(smHKOpenPrev, smHKClosePrev); + + // + double smHKDown = MathMin(smHKOpen, smHKClose); + double smHKDownPrev = MathMin(smHKOpenPrev, smHKClosePrev); + + // + double rawHKUp = MathMax(rawHKOpen, rawHKClose); + double rawHKUpPrev = MathMax(rawHKOpenPrev, rawHKClosePrev); + + // + double rawHKDown = MathMin(rawHKOpen, rawHKClose); + double rawHKDownPrev = MathMin(rawHKOpenPrev, rawHKClosePrev); + + // + XOHCL rawHKCBar; + bool hasRawHKBar = GetRawHKAsXOHCL( + cIndex, + rawHKCBar // + ); + + // + // + // + + // + bool isSMHKBullish = smHKOpen < smHKClose; + bool isSMHKBullishPrev = smHKOpenPrev < smHKClosePrev; + + // + bool isRawHKBullish = rawHKOpen < rawHKClose; + bool isRawHKBullishPrev = rawHKOpenPrev < rawHKClosePrev; + + // + bool isSMHKSwitchedToBullish = isSMHKBullish && + !isSMHKBullishPrev; + bool isRawHKSwitchedToBullish = isRawHKBullish && + !isRawHKBullishPrev; + + // + bool isSMHKBearish = smHKOpen > smHKClose; + bool isSMHKBearishPrev = smHKOpenPrev > smHKClosePrev; + + // + bool isRawHKBearish = rawHKOpen > rawHKClose; + bool isRawHKBearishPrev = rawHKOpenPrev > rawHKClosePrev; + + // + bool isSMHKSwitchedToBearish = isSMHKBearish && + !isSMHKBearishPrev; + bool isRawHKSwitchedToBearish = isRawHKBearish && + !isRawHKBearishPrev; + + // + bool isClosedOverSMHK = cBar.close > smHKUp; + bool isClosedUnderSMHK = cBar.close < smHKDown; + + // + bool isClosedOverRawHK = cBar.close > rawHKUp; + bool isClosedUnderRawHK = cBar.close < rawHKDown; + + // + bool isRawHKClosedOverSMHK = rawHKClose > smHKUp; + bool isRawHKClosedUnderSMHK = rawHKClose < smHKDown; + + // + bool isBreakedUpSMHK = IsBarBreak( + smHKUp, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpRawHK = IsBarBreak( + rawHKUp, + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedUpSMHK = IsBarReject( + smHKUp, + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedUpRawHK = IsBarReject( + rawHKUp, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isRawHKBreakedUpSMHK = + hasRawHKBar && + IsBarBreak( + smHKUp, + X_DIRECTION_BULLISH, + rawHKCBar // + ); + + // + bool isBreakedDownSMHK = IsBarBreak( + smHKDown, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownRawHK = IsBarBreak( + rawHKDown, + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDownSMHK = IsBarReject( + smHKDown, + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDownRawHK = IsBarReject( + rawHKDown, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRawHKBreakedDownSMHK = + hasRawHKBar && + IsBarBreak( + smHKDown, + X_DIRECTION_BEARISH, + rawHKCBar // + ); + + // + conditions.isSMHKBullish = isSMHKBullish; + conditions.isRawHKBullish = isRawHKBullish; + conditions.isSMHKSwitchedToBullish = isSMHKSwitchedToBullish; + conditions.isRawHKSwitchedToBullish = isRawHKSwitchedToBullish; + conditions.isSMHKBearish = isSMHKBearish; + conditions.isRawHKBearish = isRawHKBearish; + conditions.isSMHKSwitchedToBearish = isSMHKSwitchedToBearish; + conditions.isRawHKSwitchedToBearish = isRawHKSwitchedToBearish; + conditions.isClosedOverSMHK = isClosedOverSMHK; + conditions.isClosedUnderSMHK = isClosedUnderSMHK; + conditions.isClosedOverRawHK = isClosedOverRawHK; + conditions.isClosedUnderRawHK = isClosedUnderRawHK; + conditions.isRawHKClosedOverSMHK = isRawHKClosedOverSMHK; + conditions.isRawHKClosedUnderSMHK = isRawHKClosedUnderSMHK; + conditions.isBreakedUpSMHK = isBreakedUpSMHK; + conditions.isBreakedUpRawHK = isBreakedUpRawHK; + conditions.isRejectedUpSMHK = isRejectedUpSMHK; + conditions.isRejectedUpRawHK = isRejectedUpRawHK; + conditions.isRawHKBreakedUpSMHK = isRawHKBreakedUpSMHK; + conditions.isBreakedDownSMHK = isBreakedDownSMHK; + conditions.isBreakedDownRawHK = isBreakedDownRawHK; + conditions.isRejectedDownSMHK = isRejectedDownSMHK; + conditions.isRejectedDownRawHK = isRejectedDownRawHK; + conditions.isRawHKBreakedDownSMHK = isRawHKBreakedDownSMHK; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + rawHKCBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XHKInputs mInputs; // Inputs ... + + // + // Buffers ... + double xhkRawOpenBuffer[]; + double xhkRawHighBuffer[]; + double xhkRawLowBuffer[]; + double xhkRawCloseBuffer[]; + double xhkSMOpenBuffer[]; + double xhkSMHighBuffer[]; + double xhkSMLowBuffer[]; + double xhkSMCloseBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // RAW Open ... + CopyBuffer( + mHandler, + X121_XHK_RAW_OPEN_LINE, + 0, + maxRequiredBars, + xhkRawOpenBuffer + // + ); + + // + // RAW High ... + CopyBuffer( + mHandler, + X121_XHK_RAW_HIGH_LINE, + 0, + maxRequiredBars, + xhkRawHighBuffer + // + ); + + // + // RAW Low ... + CopyBuffer( + mHandler, + X121_XHK_RAW_LOW_LINE, + 0, + maxRequiredBars, + xhkRawLowBuffer + // + ); + + // + // RAW Close ... + CopyBuffer( + mHandler, + X121_XHK_RAW_CLOSE_LINE, + 0, + maxRequiredBars, + xhkRawCloseBuffer + // + ); + + // + // SM Open ... + CopyBuffer( + mHandler, + X121_XHK_SM_OPEN_LINE, + 0, + maxRequiredBars, + xhkSMOpenBuffer + // + ); + + // + // SM High ... + CopyBuffer( + mHandler, + X121_XHK_SM_HIGH_LINE, + 0, + maxRequiredBars, + xhkSMHighBuffer + // + ); + + // + // SM Low ... + CopyBuffer( + mHandler, + X121_XHK_SM_LOW_LINE, + 0, + maxRequiredBars, + xhkSMLowBuffer + // + ); + + // + // SM Close ... + CopyBuffer( + mHandler, + X121_XHK_SM_CLOSE_LINE, + 0, + maxRequiredBars, + xhkSMCloseBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + xhkRawOpenBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkRawHighBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkRawLowBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkRawCloseBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkSMOpenBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkSMHighBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkSMLowBuffer, + maxAllowed // + ); + + // + CleanupArray( + xhkSMCloseBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xpv.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xpv.helper.mq5 new file mode 100644 index 0000000..993a184 --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xpv.helper.mq5 @@ -0,0 +1,2551 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XPVHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XPV_BUFFERS +{ + // + X121_XPV_PEAK_LINE = 0, + X121_XPV_VALE_LINE = 1, + X121_XPV_SAR_LINE = 2, + X121_XPV_PEAK_GOLDEN_ZONE_LINE = 3, + X121_XPV_VALE_GOLDEN_ZONE_LINE = 4, + X121_XPV_C_HH_LINE = 5, + X121_XPV_C_LL_LINE = 6, + X121_XPV_S_HH_LINE = 7, + X121_XPV_S_LL_LINE = 8, + X121_XPV_M_HH_LINE = 9, + X121_XPV_M_LL_LINE = 10, + X121_XPV_L_HH_LINE = 11, + X121_XPV_L_LL_LINE = 12, + X121_XPV_H_HH_LINE = 13, + X121_XPV_H_LL_LINE = 14, +}; + +// +// Input Models ... +struct X121XPVInputs +{ + // + // Props ... + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod; // How to Find Period + ENUM_TIMEFRAMES scPeriod; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod; // How to Find Period + ENUM_TIMEFRAMES mcPeriod; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod; // How to Find Period + ENUM_TIMEFRAMES lcPeriod; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod; // How to Find Period + ENUM_TIMEFRAMES hcPeriod; // Time Period + + // + // Boundary Detection ... + ENUM_SERIESMODE hhMode; // Highest High Calculation Method + ENUM_SERIESMODE llMode; // Lowest Low Calculation Method + ENUM_X_FIBO_LEVELS goldenZoneLevel; // Golden Zone Detection + + // + // Parabolic Sar Detection ... + double sarStep; // Step + double sarMax; // Maximum + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + int sarArrowCode; // Parabolic Sar Arrow Code + int peaksArrowCode; // Peaks Arrow Code + int valesArrowCode; // Vales Arrow Code + + // + bool showSar; // Show Parabolic Sar + bool showPeaks; // Show Peaks + bool showVales; // Show Vales + bool showGoldenZones; // Show Golden Zones + + // + // Constructor(s) ... + X121XPVInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + // Short ... + scMethod = X_PERIOD_NOTHING; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_NOTHING; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_NOTHING; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_NOTHING; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + goldenZoneLevel = X_FIBO_LEVEL_382; + + // + sarStep = 0; + sarMax = 0; + + // + startCalculationForLastBars = 0; + + // + sarArrowCode = 0; + peaksArrowCode = 0; + valesArrowCode = 0; + + // + showSar = false; + showPeaks = false; + showVales = false; + showGoldenZones = true; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + // Short ... + scMethod = X_PERIOD_AUTO; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_AUTO; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_AUTO; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_AUTO; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + goldenZoneLevel = X_FIBO_LEVEL_382; + + // + sarStep = 0.02; + sarMax = 0.2; + + // + startCalculationForLastBars = 1000; + + // + sarArrowCode = 159; + peaksArrowCode = 159; + valesArrowCode = 159; + + // + showSar = true; + showPeaks = true; + showVales = true; + showGoldenZones = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, 1); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XPVConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double peaksGoldenBuffer[]; + double valesGoldenBuffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + + // + // Conditions ... + + // + // SAR ... + + // + bool isSarBullish; + bool isSarBearish; + + // + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + // XPV ... + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + bool isRejectedPrevPeak; + bool isBreakedUpPrevPeak; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + bool isRejectedPrevVale; + bool isBreakedDownPrevVale; + + // + // Constructor ... + X121XPVConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(peaksGoldenBuffer); + Clean(valesGoldenBuffer); + Clean(sarBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + + // + // Clean(bullishTrendBuffer); + // Clean(bearishTrendBuffer); + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(peaksGoldenBuffer, true); + ArraySetAsSeries(valesGoldenBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + + // + // Conditions ... + + // + isSarBullish = false; + isSarBearish = false; + + // + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + isRejectedPrevPeak = false; + isBreakedUpPrevPeak = false; + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + isRejectedPrevVale = false; + isBreakedDownPrevVale = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevPeak", isRejectedPrevPeak, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevPeak", isBreakedUpPrevPeak, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevVale", isRejectedPrevVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevVale", isBreakedDownPrevVale, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XPVHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XPVHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XPVHelper() + { + // + mInputs.Clean(); + + // + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(peaksGoldenBuffer); + Clean(valesGoldenBuffer); + Clean(sarBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XPVInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(peaksGoldenBuffer, true); + ArraySetAsSeries(valesGoldenBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xpv", + // + // Inputs ... + // + // Market ... + "", + // + // Short ... + "", + mInputs.scMethod, + mInputs.scPeriod, + // + // Medium ... + "", + mInputs.mcMethod, + mInputs.mcPeriod, + // + // Long ... + "", + mInputs.lcMethod, + mInputs.lcPeriod, + // + // Hind ... + "", + mInputs.hcMethod, + mInputs.hcPeriod, + // + // Boundary Detection ... + "", + mInputs.hhMode, + mInputs.llMode, + mInputs.goldenZoneLevel, + // + // SAr Detection ... + "", + mInputs.sarStep, + mInputs.sarMax, + // + // Presentation ... + "", + // + mInputs.startCalculationForLastBars, + mInputs.sarArrowCode, + mInputs.peaksArrowCode, + mInputs.valesArrowCode, + // + mInputs.showSar, + mInputs.showPeaks, + mInputs.showVales, + mInputs.showGoldenZones + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XPVInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XPVInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // SAR ... + + // + double GetSar( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sarBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sarBuffer[barIndex]; + } + + // + int CopySar( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // PV ... + + // + // PEAKS ... + + // + double GetPeak( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(peaksBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return peaksBuffer[barIndex]; + } + + // + int CopyPeak( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + peaksBuffer, + buffer, + forceClean + // + ); + } + + // + // VALES ... + + // + double GetVale( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(valesBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return valesBuffer[barIndex]; + } + + // + int CopyVale( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + valesBuffer, + buffer, + forceClean + // + ); + } + + // + // GOLDEN PEAKS ... + + // + double GetPeakGoldenZone( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(peaksGoldenBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return peaksGoldenBuffer[barIndex]; + } + + // + int CopyPeakGoldenZone( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + peaksGoldenBuffer, + buffer, + forceClean + // + ); + } + + // + // GOLDEN VALES ... + + // + double GetValeGoldenZone( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(valesGoldenBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return valesGoldenBuffer[barIndex]; + } + + // + int CopyValeGoldenZone( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + valesGoldenBuffer, + buffer, + forceClean + // + ); + } + + // + // + // + + // + double GetHigherPeak( + int &index, // Bar Index + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(sIndex); + if (iValue > peak) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetLowerPeak( + int &index, // Bar Index + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(sIndex); + if (iValue < peak) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetHigherVale( + int &index, // Bar Index + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(sIndex); + if (iValue > vale) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetLowerVale( + int &index, // Bar Index + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(sIndex); + if (iValue < vale) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + // CURRENT ... + + // + // HH ... + + // + double GetCHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cHHBuffer[barIndex]; + } + + // + int CopyCHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetCLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cLLBuffer[barIndex]; + } + + // + int CopyCLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cLLBuffer, + buffer, + forceClean + // + ); + } + + // + // SHORT ... + + // + // HH ... + + // + double GetSHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sHHBuffer[barIndex]; + } + + // + int CopySHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetSLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sLLBuffer[barIndex]; + } + + // + int CopySLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sLLBuffer, + buffer, + forceClean + // + ); + } + + // + // MEDIUM ... + + // + // HH ... + + // + double GetMHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mHHBuffer[barIndex]; + } + + // + int CopyMHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetMLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mLLBuffer[barIndex]; + } + + // + int CopyMLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mLLBuffer, + buffer, + forceClean + // + ); + } + + // + // LONG ... + + // + // HH ... + + // + double GetLHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lHHBuffer[barIndex]; + } + + // + int CopyLHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetLLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lLLBuffer[barIndex]; + } + + // + int CopyLLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lLLBuffer, + buffer, + forceClean + // + ); + } + + // + // HIND ... + + // + // HH ... + + // + double GetHHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hHHBuffer[barIndex]; + } + + // + int CopyHHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetHLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hLLBuffer[barIndex]; + } + + // + int CopyHLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hLLBuffer, + buffer, + forceClean + // + ); + } + + // + // Tools Function ... + + // + double GetLowestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetHighestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetLowestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + double GetHighestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XPVConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopySar( + zIndex, + loopback, + conditions.sarBuffer // + ); + + // + CopyPeak( + zIndex, + loopback, + conditions.peaksBuffer // + ); + + // + CopyVale( + zIndex, + loopback, + conditions.valesBuffer // + ); + + // + CopyPeakGoldenZone( + zIndex, + loopback, + conditions.peaksGoldenBuffer // + ); + + // + CopyValeGoldenZone( + zIndex, + loopback, + conditions.valesGoldenBuffer // + ); + + // + CopyCHH( + zIndex, + loopback, + conditions.cHHBuffer // + ); + + // + CopyCLL( + zIndex, + loopback, + conditions.cLLBuffer // + ); + + // + CopySHH( + zIndex, + loopback, + conditions.sHHBuffer // + ); + + // + CopySLL( + zIndex, + loopback, + conditions.sLLBuffer // + ); + + // + CopyMHH( + zIndex, + loopback, + conditions.mHHBuffer // + ); + + // + CopyMLL( + zIndex, + loopback, + conditions.mLLBuffer // + ); + + // + CopyLHH( + zIndex, + loopback, + conditions.lHHBuffer // + ); + + // + CopyLLL( + zIndex, + loopback, + conditions.lLLBuffer // + ); + + // + CopyHHH( + zIndex, + loopback, + conditions.hHHBuffer // + ); + + // + CopyHLL( + zIndex, + loopback, + conditions.hLLBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // SAR ... + + // + bool isSarBullish = conditions.sarBuffer[cIDX] < cBar.low; + bool isSarBullishPrev = conditions.sarBuffer[pIDX] < pBar.low; + + // + bool isSarBearish = conditions.sarBuffer[cIDX] > cBar.high; + bool isSarBearishPrev = conditions.sarBuffer[pIDX] > pBar.high; + + // + bool isSarSwitchedToBullish = isSarBullish && + !isSarBullishPrev; + bool isSarSwitchedToBearish = isSarBearish && + !isSarBearishPrev; + + // + // XPV ... + + // + bool isNewPeak = conditions.peaksBuffer[cIDX] != conditions.peaksBuffer[pIDX]; + bool isNewPeakOverLast = isNewPeak && + conditions.peaksBuffer[cIDX] > conditions.peaksBuffer[pIDX]; + bool isNewPeakUnderLast = isNewPeak && + conditions.peaksBuffer[cIDX] < conditions.peaksBuffer[pIDX]; + bool isRejectedPrevPeak = IsBarReject( + conditions.peaksBuffer[pIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedUpPrevPeak = IsBarBreak( + conditions.peaksBuffer[pIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isNewVale = conditions.valesBuffer[cIDX] != conditions.valesBuffer[pIDX]; + bool isNewValeOverLast = isNewVale && + conditions.valesBuffer[cIDX] > conditions.valesBuffer[pIDX]; + bool isNewValeUnderLast = isNewVale && + conditions.valesBuffer[cIDX] < conditions.valesBuffer[pIDX]; + bool isRejectedPrevVale = IsBarReject( + conditions.valesBuffer[pIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevVale = IsBarBreak( + conditions.valesBuffer[pIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + conditions.isSarBullish = isSarBullish; + conditions.isSarBearish = isSarBearish; + conditions.isSarSwitchedToBullish = isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = isSarSwitchedToBearish; + conditions.isNewPeak = isNewPeak; + conditions.isNewPeakOverLast = isNewPeakOverLast; + conditions.isNewPeakUnderLast = isNewPeakUnderLast; + conditions.isRejectedPrevPeak = isRejectedPrevPeak; + conditions.isBreakedUpPrevPeak = isBreakedUpPrevPeak; + conditions.isNewVale = isNewVale; + conditions.isNewValeOverLast = isNewValeOverLast; + conditions.isNewValeUnderLast = isNewValeUnderLast; + conditions.isRejectedPrevVale = isRejectedPrevVale; + conditions.isBreakedDownPrevVale = isBreakedDownPrevVale; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XPVInputs mInputs; // Inputs ... + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double peaksGoldenBuffer[]; + double valesGoldenBuffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // SAR ... + CopyBuffer( + mHandler, + X121_XPV_SAR_LINE, + 0, + maxRequiredBars, + sarBuffer + // + ); + + // + // XPV ... + + // + // PEAKS ... + CopyBuffer( + mHandler, + X121_XPV_PEAK_LINE, + 0, + maxRequiredBars, + peaksBuffer + // + ); + + // + // VALES ... + CopyBuffer( + mHandler, + X121_XPV_VALE_LINE, + 0, + maxRequiredBars, + valesBuffer + // + ); + + // + // GOLDEN PEAKS ... + CopyBuffer( + mHandler, + X121_XPV_PEAK_GOLDEN_ZONE_LINE, + 0, + maxRequiredBars, + peaksGoldenBuffer + // + ); + + // + // GOLDEN VALES ... + CopyBuffer( + mHandler, + X121_XPV_VALE_GOLDEN_ZONE_LINE, + 0, + maxRequiredBars, + valesGoldenBuffer + // + ); + + // + // CURRENT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_C_HH_LINE, + 0, + maxRequiredBars, + cHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_C_LL_LINE, + 0, + maxRequiredBars, + cLLBuffer + // + ); + + // + // SHORT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_S_HH_LINE, + 0, + maxRequiredBars, + sHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_S_LL_LINE, + 0, + maxRequiredBars, + sLLBuffer + // + ); + + // + // MEDIUM ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_M_HH_LINE, + 0, + maxRequiredBars, + mHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_M_LL_LINE, + 0, + maxRequiredBars, + mLLBuffer + // + ); + + // + // LONG ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_L_HH_LINE, + 0, + maxRequiredBars, + lHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_L_LL_LINE, + 0, + maxRequiredBars, + lLLBuffer + // + ); + + // + // HIND ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_H_HH_LINE, + 0, + maxRequiredBars, + hHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_H_LL_LINE, + 0, + maxRequiredBars, + hLLBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + peaksBuffer, + maxAllowed // + ); + + // + CleanupArray( + valesBuffer, + maxAllowed // + ); + + // + CleanupArray( + peaksGoldenBuffer, + maxAllowed // + ); + + // + CleanupArray( + valesGoldenBuffer, + maxAllowed // + ); + + // + CleanupArray( + sarBuffer, + maxAllowed // + ); + + // + CleanupArray( + cHHBuffer, + maxAllowed // + ); + + // + CleanupArray( + cLLBuffer, + maxAllowed // + ); + + // + CleanupArray( + sHHBuffer, + maxAllowed // + ); + + // + CleanupArray( + sLLBuffer, + maxAllowed // + ); + + // + CleanupArray( + mHHBuffer, + maxAllowed // + ); + + // + CleanupArray( + mLLBuffer, + maxAllowed // + ); + + // + CleanupArray( + lHHBuffer, + maxAllowed // + ); + + // + CleanupArray( + lLLBuffer, + maxAllowed // + ); + + // + CleanupArray( + hHHBuffer, + maxAllowed // + ); + + // + CleanupArray( + hLLBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xstr.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xstr.helper.mq5 new file mode 100644 index 0000000..31bf24f --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xstr.helper.mq5 @@ -0,0 +1,1112 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XSTRHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XSTR_BUFFERS +{ + // + X121_XSTR_LINE = 0, + X121_XSTR_UP_LINE = 2, + X121_XSTR_DOWN_LINE = 3, + X121_XSTR_ATR_LINE = 4, + X121_XSTR_PRICE_LINE = 5, + X121_XSTR_STATE_LINE = 6, +}; + +// +// Input Models ... +struct X121XSTRInputs +{ + // + // Props ... + + int strLength; // Length + double strMultiplier; // Multiplier + ENUM_APPLIED_PRICE strAppliedTo; // Applied To + + // + bool showStr; // Show Upper Zone + bool showStrUpper; // Show Str Upper + bool showStrLower; // Show Str Lower + + // + // Constructor(s) ... + X121XSTRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + strLength = 0; + strMultiplier = 0.0; + strAppliedTo = PRICE_MEDIAN; + + // + showStr = false; + showStrUpper = false; + showStrLower = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + strLength = 14; + strMultiplier = 3.0; + strAppliedTo = PRICE_MEDIAN; + + // + showStr = true; + showStrUpper = true; + showStrLower = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + strLength > 0 && + strMultiplier > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, strLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XSTRConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double strBuffer[]; + double atrBuffer[]; + double strPriceBuffer[]; + double strUpBuffer[]; + double strDownBuffer[]; + double strStateBuffer[]; + + // + // Conditions ... + + // + bool isStrBullish; + bool isStrBearish; + + // + bool isStrSwitchedToBullish; + bool isStrSwitchedToBearish; + + // + // bool isCloseLower + + // + // Constructor ... + X121XSTRConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(strBuffer); + Clean(atrBuffer); + Clean(strPriceBuffer); + Clean(strUpBuffer); + Clean(strDownBuffer); + Clean(strStateBuffer); + + // + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + + // + // Conditions ... + + // + isStrBullish = false; + isStrBearish = false; + + // + isStrSwitchedToBullish = false; + isStrSwitchedToBearish = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isStrBullish", isStrBullish, ignoreFalseConditions, separator) + + ToString("isStrBearish", isStrBearish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBullish", isStrSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBearish", isStrSwitchedToBearish, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XSTRHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XSTRHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XSTRHelper() + { + // + mInputs.Clean(); + + // + Clean(strBuffer); + Clean(atrBuffer); + Clean(strPriceBuffer); + Clean(strUpBuffer); + Clean(strDownBuffer); + Clean(strStateBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XSTRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // Market ... + "", + mInputs.strLength, + mInputs.strMultiplier, + mInputs.strAppliedTo, + // + // Presentation ... + "", + mInputs.showStr, + mInputs.showStrUpper, + mInputs.showStrLower + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XSTRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XSTRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strBuffer[barIndex]; + } + + // + int CopySTR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strStateBuffer[barIndex]; + } + + // + int CopySTRState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strStateBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strPriceBuffer[barIndex]; + } + + // + int CopySTRPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strPriceBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRUp( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strUpBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strUpBuffer[barIndex]; + } + + // + int CopySTRUp( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strUpBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRDown( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strDownBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strDownBuffer[barIndex]; + } + + // + int CopySTRDown( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strDownBuffer, + buffer, + forceClean + // + ); + } + + // + double GetLastSTR( + ENUM_X_DIRECTION dir, + int barIndex = 0 // + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!HasDirection(dir)) + { + return result; + } + + // + int index = barIndex; + bool isBullish = IsBullish(dir); + + // + bool canContinue = true; + while (canContinue) + { + // + double iStr = GetSTR(index); + double iState = GetSTRState(index); + + // + canContinue = + isBullish + ? iState < 0 + : iState > 0; + if (!canContinue) + { + // + result = iStr; + break; + } + + // + index++; + } + + // + return result; + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XSTRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyATR( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopySTR( + zIndex, + loopback, + conditions.strBuffer // + ); + + // + CopySTRState( + zIndex, + loopback, + conditions.strStateBuffer // + ); + + // + CopySTRPrice( + zIndex, + loopback, + conditions.strPriceBuffer // + ); + + // + CopySTRUp( + zIndex, + loopback, + conditions.strUpBuffer // + ); + + // + CopySTRDown( + zIndex, + loopback, + conditions.strDownBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isStrBullish = strStateBuffer[cIDX] > 0; + bool isStrBullishPrev = strStateBuffer[pIDX] > 0; + + // + bool isStrBearish = strStateBuffer[cIDX] < 0; + bool isStrBearishPrev = strStateBuffer[pIDX] < 0; + + // + bool isStrSwitchedToBullish = isStrBullish && + !isStrBullishPrev; + bool isStrSwitchedToBearish = isStrBearish && + !isStrBearishPrev; + + // + conditions.isStrBullish = isStrBullish; + conditions.isStrBearish = isStrBearish; + conditions.isStrSwitchedToBullish = isStrSwitchedToBullish; + conditions.isStrSwitchedToBearish = isStrSwitchedToBearish; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XSTRInputs mInputs; // Inputs ... + + // + // Buffers ... + double strBuffer[]; + double atrBuffer[]; + double strPriceBuffer[]; + double strUpBuffer[]; + double strDownBuffer[]; + double strStateBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // STR ... + CopyBuffer( + mHandler, + X121_XSTR_LINE, + 0, + maxRequiredBars, + strBuffer + // + ); + + // + // State ... + CopyBuffer( + mHandler, + X121_XSTR_STATE_LINE, + 0, + maxRequiredBars, + strStateBuffer + // + ); + + // + // Price ... + CopyBuffer( + mHandler, + X121_XSTR_PRICE_LINE, + 0, + maxRequiredBars, + strPriceBuffer + // + ); + + // + // Up ... + CopyBuffer( + mHandler, + X121_XSTR_UP_LINE, + 0, + maxRequiredBars, + strUpBuffer + // + ); + + // + // STR ... + CopyBuffer( + mHandler, + X121_XSTR_DOWN_LINE, + 0, + maxRequiredBars, + strDownBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_XSTR_ATR_LINE, + 0, + maxRequiredBars, + atrBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + strBuffer, + maxAllowed // + ); + + // + CleanupArray( + atrBuffer, + maxAllowed // + ); + + // + CleanupArray( + strPriceBuffer, + maxAllowed // + ); + + // + CleanupArray( + strUpBuffer, + maxAllowed // + ); + + // + CleanupArray( + strDownBuffer, + maxAllowed // + ); + + // + CleanupArray( + strStateBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xtrend.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xtrend.helper.mq5 new file mode 100644 index 0000000..1f5a7aa --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xtrend.helper.mq5 @@ -0,0 +1,1279 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XTRENDHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XTREND_BUFFERS +{ + // + X121_XTREND_UP_LINE = 0, + X121_XTREND_DOWN_LINE = 1, + X121_XTREND_MA_LINE = 2, + X121_XTREND_ADX_LINE = 3, + X121_XTREND_ADX_P_LINE = 4, + X121_XTREND_ADX_M_LINE = 5, + X121_XTREND_UP_T_LINE = 6, + X121_XTREND_DOWN_T_LINE = 7, +}; + +// +// Input Models ... +struct X121XTRENDInputs +{ + // + // Props ... + // + // Market ... + ENUM_APPLIED_PRICE trendPriceType; // Detect Trend Price Type + + // + // MA Detection ... + int maLength; // MA Length + ENUM_MA_METHOD maMethod; // MA Method + ENUM_APPLIED_PRICE maAppliedTo; // MA Applied To + + // + // ADX Detection ... + int adxLength; // ADX Length + double adxThreshold; // ADX Threshold for Strong Trends + + // + // Presentation ... + + // + int startCalculationForLastBars; // Calculate Last n Bars + int upTrendArrowCode; // Up Trend Arrow Code + int downTrendArrowCode; // Down Trend Arrow Code + + // + bool showOnlyTrendStart; // Show Only Trend Start + bool showUpTrend; // Show Up Trend + bool showDownTrend; // Show Down Trend + + // + // Constructor(s) ... + X121XTRENDInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + trendPriceType = PRICE_CLOSE; + maLength = 50; + maMethod = MODE_EMA; + maAppliedTo = PRICE_CLOSE; + adxLength = 14; + adxThreshold = 25; + startCalculationForLastBars = 1000; + upTrendArrowCode = 233; + downTrendArrowCode = 234; + showOnlyTrendStart = false; + showUpTrend = false; + showDownTrend = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + trendPriceType = PRICE_CLOSE; + maLength = 50; + maMethod = MODE_EMA; + maAppliedTo = PRICE_CLOSE; + adxLength = 14; + adxThreshold = 25; + startCalculationForLastBars = 1000; + upTrendArrowCode = 233; + downTrendArrowCode = 234; + showOnlyTrendStart = true; + showUpTrend = true; + showDownTrend = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + // MA ... + maLength > 0 && + // + // ADX ... + adxLength > 0 && + adxThreshold > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(maLength, adxLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XTRENDConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double upTrendBuffer[]; + double downTrendBuffer[]; + double maBuffer[]; + double adxBuffer[]; + double adxPBuffer[]; + double adxMBuffer[]; + double upTBuffer[]; + double downTBuffer[]; + + // + // Conditions ... + + // + bool isTrendBullish; + bool isTrendBearish; + + // + bool isTrendSwitchedToBullish; + bool isTrendSwitchedToBearish; + + // + // bool isCloseLower + + // + // Constructor ... + X121XTRENDConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(upTrendBuffer); + Clean(downTrendBuffer); + Clean(maBuffer); + Clean(adxBuffer); + Clean(adxPBuffer); + Clean(adxMBuffer); + Clean(upTBuffer); + Clean(downTBuffer); + + // + ArraySetAsSeries(upTrendBuffer, true); + ArraySetAsSeries(downTrendBuffer, true); + ArraySetAsSeries(maBuffer, true); + ArraySetAsSeries(adxBuffer, true); + ArraySetAsSeries(adxPBuffer, true); + ArraySetAsSeries(adxMBuffer, true); + ArraySetAsSeries(upTBuffer, true); + ArraySetAsSeries(downTBuffer, true); + + // + // Conditions ... + + // + isTrendBullish = false; + isTrendBearish = false; + + // + isTrendSwitchedToBullish = false; + isTrendSwitchedToBearish = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isTrendBullish", isTrendBullish, ignoreFalseConditions, separator) + + ToString("isTrendBearish", isTrendBearish, ignoreFalseConditions, separator) + + ToString("isTrendSwitchedToBullish", isTrendSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isTrendSwitchedToBearish", isTrendSwitchedToBearish, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XTRENDHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XTRENDHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XTRENDHelper() + { + // + mInputs.Clean(); + + // + Clean(upTrendBuffer); + Clean(downTrendBuffer); + Clean(maBuffer); + Clean(adxBuffer); + Clean(adxPBuffer); + Clean(adxMBuffer); + Clean(upTBuffer); + Clean(downTBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XTRENDInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(upTrendBuffer, true); + ArraySetAsSeries(downTrendBuffer, true); + ArraySetAsSeries(maBuffer, true); + ArraySetAsSeries(adxBuffer, true); + ArraySetAsSeries(adxPBuffer, true); + ArraySetAsSeries(adxMBuffer, true); + ArraySetAsSeries(upTBuffer, true); + ArraySetAsSeries(downTBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xtrend", + // + // Inputs ... + // + // Market ... + "", + mInputs.trendPriceType, + // + // MA Detection ... + "", + mInputs.maLength, + mInputs.maMethod, + mInputs.maAppliedTo, + // + // ADX Detection ... + "", + mInputs.adxLength, + mInputs.adxThreshold, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + mInputs.upTrendArrowCode, + mInputs.downTrendArrowCode, + mInputs.showOnlyTrendStart, + mInputs.showUpTrend, + mInputs.showDownTrend + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XTRENDInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XTRENDInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // Up Trend ... + + // + double GetUpTrend( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(upTrendBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return upTrendBuffer[barIndex]; + } + + // + int CopyUpTrend( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + upTrendBuffer, + buffer, + forceClean + // + ); + } + + // + // Down Trend ... + + // + double GetDownTrend( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(downTrendBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return downTrendBuffer[barIndex]; + } + + // + int CopyDownTrend( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + downTrendBuffer, + buffer, + forceClean + // + ); + } + + // + // Ma ... + + // + double GetMA( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(downTrendBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return downTrendBuffer[barIndex]; + } + + // + int CopyMA( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + downTrendBuffer, + buffer, + forceClean + // + ); + } + + // + // ADX ... + + // + double GetADX( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(adxBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return adxBuffer[barIndex]; + } + + // + int CopyADX( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + adxBuffer, + buffer, + forceClean + // + ); + } + + // + // ADX P... + + // + double GetADXP( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(adxPBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return adxPBuffer[barIndex]; + } + + // + int CopyADXP( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + adxPBuffer, + buffer, + forceClean + // + ); + } + + // + // ADX M ... + + // + double GetADXM( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(adxMBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return adxMBuffer[barIndex]; + } + + // + int CopyADXM( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + adxMBuffer, + buffer, + forceClean + // + ); + } + + // + // Up Trend ... + + // + double GetUpT( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(upTBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return upTBuffer[barIndex]; + } + + // + int CopyUpT( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + upTBuffer, + buffer, + forceClean + // + ); + } + + // + // Down Trend ... + + // + double GetDownT( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(downTBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return downTBuffer[barIndex]; + } + + // + int CopyDownT( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + downTBuffer, + buffer, + forceClean + // + ); + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XTRENDConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyUpTrend( + zIndex, + loopback, + conditions.upTrendBuffer // + ); + + // + CopyDownTrend( + zIndex, + loopback, + conditions.downTrendBuffer // + ); + + // + CopyMA( + zIndex, + loopback, + conditions.maBuffer // + ); + + // + CopyADX( + zIndex, + loopback, + conditions.adxBuffer // + ); + + // + CopyADXP( + zIndex, + loopback, + conditions.adxPBuffer // + ); + + // + CopyADXM( + zIndex, + loopback, + conditions.adxMBuffer // + ); + + // + CopyUpT( + zIndex, + loopback, + conditions.upTBuffer // + ); + + // + CopyDownT( + zIndex, + loopback, + conditions.downTBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isTrendBullish = upTBuffer[cIDX] != 0; + bool isTrendBullishPrev = upTBuffer[pIDX] != 0; + + // + bool isTrendBearish = downTBuffer[cIDX] != 0; + bool isTrendBearishPrev = downTBuffer[pIDX] != 0; + + // + bool isTrendSwitchedToBullish = isTrendBullish && + !isTrendBullishPrev; + bool isTrendSwitchedToBearish = isTrendBearish && + !isTrendBearishPrev; + + // + conditions.isTrendBullish = isTrendBullish; + conditions.isTrendBearish = isTrendBearish; + conditions.isTrendSwitchedToBullish = isTrendSwitchedToBullish; + conditions.isTrendSwitchedToBearish = isTrendSwitchedToBearish; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XTRENDInputs mInputs; // Inputs ... + + // + // Buffers ... + double upTrendBuffer[]; + double downTrendBuffer[]; + double maBuffer[]; + double adxBuffer[]; + double adxPBuffer[]; + double adxMBuffer[]; + double upTBuffer[]; + double downTBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // Up Trend ... + CopyBuffer( + mHandler, + X121_XTREND_UP_LINE, + 0, + maxRequiredBars, + upTrendBuffer + // + ); + + // + // Down Trend ... + CopyBuffer( + mHandler, + X121_XTREND_DOWN_LINE, + 0, + maxRequiredBars, + downTrendBuffer + // + ); + + // + // MA ... + CopyBuffer( + mHandler, + X121_XTREND_MA_LINE, + 0, + maxRequiredBars, + maBuffer + // + ); + + // + // ADX ... + CopyBuffer( + mHandler, + X121_XTREND_ADX_LINE, + 0, + maxRequiredBars, + adxBuffer + // + ); + + // + // ADX P ... + CopyBuffer( + mHandler, + X121_XTREND_ADX_P_LINE, + 0, + maxRequiredBars, + adxPBuffer + // + ); + + // + // ADX M ... + CopyBuffer( + mHandler, + X121_XTREND_ADX_M_LINE, + 0, + maxRequiredBars, + adxMBuffer + // + ); + + // + // Up T ... + CopyBuffer( + mHandler, + X121_XTREND_UP_T_LINE, + 0, + maxRequiredBars, + upTBuffer + // + ); + + // + // Down T ... + CopyBuffer( + mHandler, + X121_XTREND_DOWN_T_LINE, + 0, + maxRequiredBars, + downTBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + upTrendBuffer, + maxAllowed // + ); + + // + CleanupArray( + downTrendBuffer, + maxAllowed // + ); + + // + CleanupArray( + maBuffer, + maxAllowed // + ); + + // + CleanupArray( + adxBuffer, + maxAllowed // + ); + + // + CleanupArray( + adxPBuffer, + maxAllowed // + ); + + // + CleanupArray( + adxMBuffer, + maxAllowed // + ); + + // + CleanupArray( + upTBuffer, + maxAllowed // + ); + + // + CleanupArray( + downTBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Helpers/x-saherelm.x121.xvwap.helper.mq5 b/BKPS/14031218/Helpers/x-saherelm.x121.xvwap.helper.mq5 new file mode 100644 index 0000000..4f7a4ef --- /dev/null +++ b/BKPS/14031218/Helpers/x-saherelm.x121.xvwap.helper.mq5 @@ -0,0 +1,1508 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XVWAPHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XVWAP_BUFFERS +{ + // + X121_XVWAP_FAST_LINE = 0, + X121_XVWAP_FAST_STATE_LINE = 8, + X121_XVWAP_MID_LINE = 2, + X121_XVWAP_MID_STATE_LINE = 9, + X121_XVWAP_SLOW_LINE = 4, + X121_XVWAP_SLOW_STATE_LINE = 10, + X121_XVWAP_VOLUME_LINE = 6, + X121_XVWAP_PRICE_LINE = 7, +}; + +// +enum ENUM_XVWAP_STATES +{ + XVWAP_STATE_BULLISH = 1, + XVWAP_STATE_BEARISH = 2, + XVWAP_STATE_NEUTURAL = 3, +}; + +// +// Input Models ... +struct X121XVWAPInputs +{ + // + // Props ... + + int vwapFastLength; // Fast Length + int vwapMidLength; // Mid Length + int vwapSlowLength; // Slow Length + ENUM_APPLIED_PRICE vwapAppliedTo; // Applied To + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showVWapFast; // Show VWap Fast + bool showVWapMedium; // Show VWap Medium + bool showVWapSlow; // Show VWap Slow + + // + // Constructor(s) ... + X121XVWAPInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + vwapFastLength = 0; + vwapMidLength = 0; + vwapSlowLength = 0; + vwapAppliedTo = PRICE_CLOSE; + + // + startCalculationForLastBars = 0; + + // + showVWapFast = false; + showVWapMedium = false; + showVWapSlow = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + vwapFastLength = 20; + vwapMidLength = 50; + vwapSlowLength = 100; + vwapAppliedTo = PRICE_CLOSE; + + // + startCalculationForLastBars = 1000; + + // + showVWapFast = true; + showVWapMedium = true; + showVWapSlow = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(vwapFastLength, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XVWAPConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + + // + // Conditions ... + + // + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapFastNeutural; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapMidNeutural; + + // + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapSlowNeutural; + + // + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + + // + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + + // + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + + // + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + + // + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + + // + // Constructor ... + X121XVWAPConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(vwapFastBuffer); + Clean(vwapMidBuffer); + Clean(vwapSlowBuffer); + Clean(vwapVolumeBuffer); + Clean(vwapPriceBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapMidStateBuffer); + Clean(vwapSlowStateBuffer); + + // + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + + // + // Conditions ... + + // + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastNeutural = false; + + // + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + + // + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapSlowNeutural = false; + + // + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + + // + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + + // + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + + // + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + + // + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + isVWapSwitchedToNeuturalState = false; + + // + ZeroMemory(this); + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XVWAPHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XVWAPHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XVWAPHelper() + { + // + mInputs.Clean(); + + // + Clean(vwapFastBuffer); + Clean(vwapMidBuffer); + Clean(vwapSlowBuffer); + Clean(vwapVolumeBuffer); + Clean(vwapPriceBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapMidStateBuffer); + Clean(vwapSlowStateBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XVWAPInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xvwap", + // + // Inputs ... + // + // Market ... + "", + mInputs.vwapFastLength, + mInputs.vwapMidLength, + mInputs.vwapSlowLength, + mInputs.vwapAppliedTo, + // + // Presentation ... + "", + // + mInputs.startCalculationForLastBars, + // + mInputs.showVWapFast, + mInputs.showVWapMedium, + mInputs.showVWapSlow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XVWAPInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XVWAPInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + double GetVWapFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastBuffer[barIndex]; + } + + // + int CopyVWapFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE FAST ... + + // + double GetVWapFastState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastStateBuffer[barIndex]; + } + + // + int CopyVWapFastState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastStateBuffer, + buffer, + forceClean + // + ); + } + + // + // MID ... + + // + double GetVWapMid( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidBuffer[barIndex]; + } + + // + int CopyVWapMid( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE MID ... + + // + double GetVWapMidState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidStateBuffer[barIndex]; + } + + // + int CopyVWapMidState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidStateBuffer, + buffer, + forceClean + // + ); + } + + // + // SLOW ... + + // + double GetVWapSlowBuffer( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowBuffer[barIndex]; + } + + // + int CopyVWapSlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE SLOW ... + + // + double GetVWapSlowState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowStateBuffer[barIndex]; + } + + // + int CopyVWapSlowState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowStateBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVWapVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapVolumeBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapVolumeBuffer[barIndex]; + } + + // + int CopyVWapVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapVolumeBuffer, + buffer, + forceClean + // + ); + } + + // + // PRICE ... + + // + double GetVWapPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapPriceBuffer[barIndex]; + } + + // + int CopyVWapPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapPriceBuffer, + buffer, + forceClean + // + ); + } + + // + // Converts to State ... + ENUM_XVWAP_STATES ToVWAPState(double value) + { + // + ENUM_XVWAP_STATES result = + value == 1 + ? XVWAP_STATE_BULLISH + : value == 2 + ? XVWAP_STATE_BEARISH + : XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + bool IsVWAPBullish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BULLISH; + + // + return result; + } + + // + bool IsVWAPBearish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BEARISH; + + // + return result; + } + + // + bool IsVWAPNeutural(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + void Free() override + { + Cleanup(10); + } + + // + bool GetConditions( + X121XVWAPConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyVWapFast( + zIndex, + loopback, + conditions.vwapFastBuffer // + ); + + // + CopyVWapFastState( + zIndex, + loopback, + conditions.vwapFastStateBuffer // + ); + + // + CopyVWapMid( + zIndex, + loopback, + conditions.vwapMidBuffer // + ); + + // + CopyVWapMidState( + zIndex, + loopback, + conditions.vwapMidStateBuffer // + ); + + // + CopyVWapSlow( + zIndex, + loopback, + conditions.vwapSlowBuffer // + ); + + // + CopyVWapSlowState( + zIndex, + loopback, + conditions.vwapSlowStateBuffer // + ); + + // + CopyVWapVolume( + zIndex, + loopback, + conditions.vwapVolumeBuffer // + ); + + // + CopyVWapPrice( + zIndex, + loopback, + conditions.vwapPriceBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // SAR ... + + // + bool isVWapFastBullish = IsVWAPBullish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBullishPrev = IsVWAPBullish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastBearish = IsVWAPBearish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBearishPrev = IsVWAPBearish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastNeutural = IsVWAPNeutural(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastNeuturalPrev = IsVWAPNeutural(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapMidBullish = IsVWAPBullish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBullishPrev = IsVWAPBullish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidBearish = IsVWAPBearish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBearishPrev = IsVWAPBearish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidNeutural = IsVWAPNeutural(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidNeuturalPrev = IsVWAPNeutural(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapSlowBullish = IsVWAPBullish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBullishPrev = IsVWAPBullish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowBearish = IsVWAPBearish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBearishPrev = IsVWAPBearish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowNeutural = IsVWAPNeutural(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowNeuturalPrev = IsVWAPNeutural(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapFastOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFastOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidOverSlow = conditions.vwapMidBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidOverSlowPrev = conditions.vwapMidBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFastUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidUnderSlow = conditions.vwapMidBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidUnderSlowPrev = conditions.vwapMidBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapBullishState = isVWapFastBullish && + isVWapMidBullish && + isVWapSlowBullish; + bool isVWapBullishStatePrev = isVWapFastBullishPrev && + isVWapMidBullishPrev && + isVWapSlowBullishPrev; + + // + bool isVWapBearishState = isVWapFastBearish && + isVWapMidBearish && + isVWapSlowBearish; + bool isVWapBearishStatePrev = isVWapFastBearishPrev && + isVWapMidBearishPrev && + isVWapSlowBearishPrev; + + // + bool isVWapNeuturalState = isVWapFastNeutural && + isVWapMidNeutural && + isVWapSlowNeutural; + bool isVWapNeuturalStatePrev = isVWapFastNeuturalPrev && + isVWapMidNeuturalPrev && + isVWapSlowNeuturalPrev; + + // + bool isVWapBullishOrdered = isVWapFastOverMid && + isVWapMidOverSlow; + bool isVWapBullishOrderedPrev = isVWapFastOverMidPrev && + isVWapMidOverSlowPrev; + + // + bool isVWapBearishOrdered = isVWapFastUnderMid && + isVWapMidUnderSlow; + bool isVWapBearishOrderedPrev = isVWapFastUnderMidPrev && + isVWapMidUnderSlowPrev; + + // + bool isVWapSwitchedToBullishOrdered = isVWapBullishOrdered && + !isVWapBullishOrderedPrev; + bool isVWapSwitchedToBearishOrdered = isVWapBearishOrdered && + !isVWapBearishOrderedPrev; + + // + bool isVWapSwitchedToBullishState = isVWapBullishState && + !isVWapBullishStatePrev; + bool isVWapSwitchedToBearishState = isVWapBearishState && + !isVWapBearishStatePrev; + bool isVWapSwitchedToNeuturalState = isVWapNeuturalState && + !isVWapNeuturalStatePrev; + + // + conditions.isVWapFastBullish = isVWapFastBullish; + conditions.isVWapFastBearish = isVWapFastBearish; + conditions.isVWapFastNeutural = isVWapFastNeutural; + conditions.isVWapMidBullish = isVWapMidBullish; + conditions.isVWapMidBearish = isVWapMidBearish; + conditions.isVWapMidNeutural = isVWapMidNeutural; + conditions.isVWapSlowBullish = isVWapSlowBullish; + conditions.isVWapSlowBearish = isVWapSlowBearish; + conditions.isVWapSlowNeutural = isVWapSlowNeutural; + conditions.isVWapFastOverMid = isVWapFastOverMid; + conditions.isVWapMidOverSlow = isVWapMidOverSlow; + conditions.isVWapFastUnderMid = isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = isVWapMidUnderSlow; + conditions.isVWapBullishState = isVWapBullishState; + conditions.isVWapBearishState = isVWapBearishState; + conditions.isVWapNeuturalState = isVWapNeuturalState; + conditions.isVWapBullishOrdered = isVWapBullishOrdered; + conditions.isVWapBearishOrdered = isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishOrdered = isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = isVWapSwitchedToBearishOrdered; + conditions.isVWapSwitchedToBullishState = isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = isVWapSwitchedToNeuturalState; + + // + Cleanup(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XVWAPInputs mInputs; // Inputs ... + + // + // Buffers ... + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + + // + void Calculate( + int maxRequiredBars = 100 // + ) + { + // + // Buffers ... + + // + // FAST ... + CopyBuffer( + mHandler, + X121_XVWAP_FAST_LINE, + 0, + maxRequiredBars, + vwapFastBuffer + // + ); + + // + // FAST STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_FAST_STATE_LINE, + 0, + maxRequiredBars, + vwapFastStateBuffer + // + ); + + // + // MID ... + CopyBuffer( + mHandler, + X121_XVWAP_MID_LINE, + 0, + maxRequiredBars, + vwapMidBuffer + // + ); + + // + // MID STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_MID_STATE_LINE, + 0, + maxRequiredBars, + vwapMidStateBuffer + // + ); + + // + // SLOW ... + CopyBuffer( + mHandler, + X121_XVWAP_SLOW_LINE, + 0, + maxRequiredBars, + vwapSlowBuffer + // + ); + + // + // SLOW STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_SLOW_STATE_LINE, + 0, + maxRequiredBars, + vwapSlowStateBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X121_XVWAP_VOLUME_LINE, + 0, + maxRequiredBars, + vwapVolumeBuffer + // + ); + + // + // PRICE ... + CopyBuffer( + mHandler, + X121_XVWAP_PRICE_LINE, + 0, + maxRequiredBars, + vwapPriceBuffer + // + ); + } + + // + void Cleanup( + int maxAllowed = 100 // + ) + { + // + CleanupArray( + vwapFastBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapMidBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapSlowBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapVolumeBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapPriceBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapFastStateBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapMidStateBuffer, + maxAllowed // + ); + + // + CleanupArray( + vwapSlowStateBuffer, + maxAllowed // + ); + + // + } + + // +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.x3ma.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.x3ma.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..9aace0491f1d2ae568cb631acfe659cf1dff5e26 GIT binary patch literal 15752 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 lKoILOru$4I@SftPTn#2^ZIv= maxLength && + // + // Slow MA ... + maMidCalculatedBars >= maxLength && + // + // Slow MA ... + maSlowCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Fast MA ... + int copiedFastMas = CopyBuffer(maFastHandler, 0, 0, limit, maFastBuffer); + + // + // Mid MA ... + int copiedMidMas = CopyBuffer(maMidHandler, 0, 0, limit, maMidBuffer); + + // + // Slow MA ... + int copiedSlowMas = CopyBuffer(maSlowHandler, 0, 0, limit, maSlowBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // Fast MA ... + copiedFastMas > 0 && + // + // Mid MA ... + copiedMidMas > 0 && + // + // Slow MA ... + copiedSlowMas > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + // + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = fastMALength > 0 && + midMALength > 0 && + slowMALength > 0 && + midMALength > fastMALength && + slowMALength > midMALength; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(fastMALength, midMALength); + result = MathMax(result, slowMALength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Fast ... + ArraySetAsSeries(maFastBuffer, true); + ArraySetAsSeries(maFastColorBuffer, true); + SetIndexBuffer(maFastBufferIndex, maFastBuffer, INDICATOR_DATA); + SetIndexBuffer(maFastColorBufferIndex, maFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Mid ... + ArraySetAsSeries(maMidBuffer, true); + ArraySetAsSeries(maMidColorBuffer, true); + SetIndexBuffer(maMidBufferIndex, maMidBuffer, INDICATOR_DATA); + SetIndexBuffer(maMidColorBufferIndex, maMidColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Slow ... + ArraySetAsSeries(maSlowBuffer, true); + ArraySetAsSeries(maSlowColorBuffer, true); + SetIndexBuffer(maSlowBufferIndex, maSlowBuffer, INDICATOR_DATA); + SetIndexBuffer(maSlowColorBufferIndex, maSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Data Buffers ... + + // + // Fast State ... + ArraySetAsSeries(maFastStateBuffer, true); + SetIndexBuffer(maFastStateBufferIndex, maFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Mid State ... + ArraySetAsSeries(maMidStateBuffer, true); + SetIndexBuffer(maMidStateBufferIndex, maMidStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow State ... + ArraySetAsSeries(maSlowStateBuffer, true); + SetIndexBuffer(maSlowStateBufferIndex, maSlowStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateValues( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + maMidBuffer[barIndex] = 0; + maFastBuffer[barIndex] = 0; + maSlowBuffer[barIndex] = 0; + + // + maFastColorBuffer[barIndex] = hideColorIDX; + maMidColorBuffer[barIndex] = hideColorIDX; + maSlowColorBuffer[barIndex] = hideColorIDX; + maFastStateBuffer[barIndex] = hideColorIDX; + maMidStateBuffer[barIndex] = hideColorIDX; + maSlowStateBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate Vales ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateValues( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Implement Colorify Mechanism ... + + // + // Calculate Applied Price ... + double iPrice = GetAppliedPrice( + maAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + double iFast = maFastBuffer[bar_index]; + double iMid = maMidBuffer[bar_index]; + double iSlow = maSlowBuffer[bar_index]; + + // + double iFastState = iPrice > iFast + ? bullishColorIDX + : iPrice < iFast + ? bearishColorIDX + : neuturalColorIDX; + double iMidState = iPrice > iMid + ? bullishColorIDX + : iPrice < iMid + ? bearishColorIDX + : neuturalColorIDX; + double iSlowState = iPrice > iSlow + ? bullishColorIDX + : iPrice < iSlow + ? bearishColorIDX + : neuturalColorIDX; + + // + maFastColorBuffer[bar_index] = + showMaFast + ? iFastState + : hideColorIDX; + maFastStateBuffer[bar_index] = iFastState; + + // + maMidColorBuffer[bar_index] = + showMaMid + ? iMidState + : hideColorIDX; + maMidStateBuffer[bar_index] = iMidState; + + // + maSlowColorBuffer[bar_index] = + showMaSlow + ? iSlowState + : hideColorIDX; + maSlowStateBuffer[bar_index] = iSlowState; +} + +// diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xatr.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xatr.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..79117c02c2f1c448125d958fc77370605a4300ae GIT binary patch literal 20756 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 D7&;35 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xatr.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xatr.mq5 new file mode 100644 index 0000000..d44a578 --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xatr.mq5 @@ -0,0 +1,648 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XATR +// Description: XATR ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XATR Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XATR" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; + +// +input group "RSI Detection"; +input int rsiLength = 14; // Length +input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "ATR Detection"; +input int atrLength = 14; // Length +input double atrMultiplier = 1; // Multiplier +input ENUM_APPLIED_PRICE atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To +input ENUM_APPLIED_PRICE atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To +input ENUM_X_MA_METHOD atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + +// +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars + +// +input bool showAtrUpper = true; // Show Upper Zone +input bool showAtrLower = true; // Show Lower Zone + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 6 +#property indicator_plots 2 + +// +// ATR ... + +// +// Upper ... + +// +#define atrUpperBufferIndex 0 +double atrUpperBuffer[]; + +#property indicator_label1 "X121 ATRU" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrYellow +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +// +// Lower ... + +// +#define atrLowerBufferIndex 1 +double atrLowerBuffer[]; + +#property indicator_label2 "X121 ATRL" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrYellow +#property indicator_style2 STYLE_SOLID +#property indicator_width2 2 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 1; + +// +// ATR ... + +#define atrBufferIndex mLastBufferIndex + 1 +double atrBuffer[]; + +#define atrUpperRawBufferIndex mLastBufferIndex + 2 +double atrUpperRawBuffer[]; + +#define atrLowerRawBufferIndex mLastBufferIndex + 3 +double atrLowerRawBuffer[]; + +// +// RSI ... +#define rsiBufferIndex mLastBufferIndex + 4 +double rsiBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// RSI Handler ... +int rsiHandler = INVALID_HANDLE; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +bool isStrTrendChanged; +bool isStrStartBearishTrend; +bool isStrStartBullishTrend; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // RSI ... + rsiHandler = iRSI( + _Symbol, + _Period, + rsiLength, + rsiAppliedTo // + ); + bool isInited = rsiHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength // + ); + isInited = atrHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(rsiHandler); + IndicatorRelease(atrHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Fill All Buffers by Zero ... + if (prev_calculated == 0) + { + } + + // + // Validate Calculated Bars ... + + // + // RSI ... + int rsiCalculatedBars = BarsCalculated(rsiHandler); + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // RSI ... + rsiCalculatedBars >= maxLength && + // + // ATR ... + atrCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // RSI ... + int copiedRsis = CopyBuffer(rsiHandler, 0, 0, limit, rsiBuffer); + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // + // RSI ... + copiedRsis > 0 && + // + // ATR ... + copiedAtrs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // RSI ... + rsiLength > 0 && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(rsiLength, atrLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // ATR ... + + // + // UPPER ... + bool canShowAtrUpper = showAtrUpper; + ENUM_DRAW_TYPE atrUpperDrawType = canShowAtrUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrUpperBuffer, true); + SetIndexBuffer(atrUpperBufferIndex, atrUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrUpperBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_SHOW_DATA, canShowAtrUpper); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_DRAW_TYPE, atrUpperDrawType); + + // + // LOWER ... + bool canShowAtrLower = showAtrLower; + ENUM_DRAW_TYPE atrLowerDrawType = canShowAtrLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrLowerBuffer, true); + SetIndexBuffer(atrLowerBufferIndex, atrLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrLowerBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_SHOW_DATA, canShowAtrLower); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_DRAW_TYPE, atrLowerDrawType); + + // + // Data Buffers ... + + // + // ATR ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrUpperRawBuffer, true); + SetIndexBuffer(atrUpperRawBufferIndex, atrUpperRawBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrLowerRawBuffer, true); + SetIndexBuffer(atrLowerRawBufferIndex, atrLowerRawBuffer, INDICATOR_CALCULATIONS); + + // + // RSI ... + + // + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateAtrZones( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // RSIS ... + rsiBuffer[barIndex] = 0; + + // + // ATRS ... + atrBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrUpperRawBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrLowerRawBuffer[barIndex] = 0; +} + +/** + * Calculate ATR Zones ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateAtrZones( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Select ATr Value ... + double atrValue = atrBuffer[bar_index]; + double appliedAtrMultiplierValue = atrValue * atrMultiplier; + + // + // Select Upper Price ... + double upperPrice = GetAppliedPrice( + atrUpperAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Select Lower Price ... + double lowerPrice = GetAppliedPrice( + atrLowerAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Calculate Raw Atrs ... + + // + // Upper ... + double atrUpperRawValue = upperPrice + appliedAtrMultiplierValue; + atrUpperRawBuffer[bar_index] = atrUpperRawValue; + + // + // Lower ... + double atrLowerRawValue = lowerPrice - appliedAtrMultiplierValue; + atrLowerRawBuffer[bar_index] = atrLowerRawValue; + + // + bool canSmooth = atrSmoothingMode != X_MA_MODE_NONE; + if (canSmooth) + { + // + // Upper ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrUpperRawBuffer, + atrUpperBuffer, + atrSmoothingMode // + ); + + // + // Lower ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrLowerRawBuffer, + atrLowerBuffer, + atrSmoothingMode // + ); + } + else + { + // + // Use Raw Values ... + atrUpperBuffer[bar_index] = atrUpperRawValue; + atrLowerBuffer[bar_index] = atrLowerRawValue; + } +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xcc.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xcc.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4427a2ae8acfdc398abb228b4c17cb1be2b2d343 GIT binary patch literal 13154 zcmdV9Q?Mv7vnIN1+qP}nwr$(CxtDF*Huth^+g`K(shLxE=HWcum+4eeNq3UU*PZ06 zN<=kSK^y@fkOe>h2mk;80ggZb{txjEk*eY}JkUKYxX`daPHFx>jQ<*B|F`0QxBu5X zUJw8P|H%RX|BC-hpixVN#%!yw`@m?-;koaaJ9%V?fOY7tW1uo!bO1)cM6?3oC1a+| z|1(S&z#hN>z!Sg;z!Jb5zyiSK-*TA%82)8u0GfYwWdOr}TGM}aQ2-kN+kYBK0F{5G z@IRg1zuy0`{J$*!LG1F+1I_?k0QCQo^MBzr{hxU0{`uwqZG``QbQl5X{zaSNzwh+l zSg|Z9R9kIch)YPQN%)yL=+MR^=s70 z%vhmd7*43}9a#p9op#F6_J$X7YCmAT3@`V#;89t*c-mGf=Rdqv_VhyD=jrHpLEX9i z4uzr)8!0V6K4TR}K5%=^i7%2C^-rN~3wk5!DvSWpCS#+O6{S_w_qaXezt}<2VH42V zWpq_4(MZ*9;l|8wObyu;t&E(sr0JE((cxKnJ!mL2QEuQC`5@G>fw!2^9O!6Gk-2Er zq|1bgQ0@WY*}3WK{2KWjXg09Ez*-|kCkuLu*p!5}Jejc_M!xw1rx64k1|KP`v!?+g zu{`We&b8nhEzpLb8*FZJ=b}VP7r;o4stO>?s#|aFiNF@0Wk)vSWvRXeC)H?#HuR)9dLE@R}zgBe0UTcyl54;<{Sd?mGd39Mau$W2Qk!>FN-LS7>8iR zbRl+0csh2NoZ7!YR8^nH$u^IKy*F@oq~*XphFL_$J?yj=&%bW(j${6ee)|_)51t_r zAfBETs(4--4Udro{!s=%JXK6hd9#C-m0K*i(NWDCcLlWgOgi9 zKgF3WKw^{`h~^sv65z+4Qobt;<8)@MmOF6lgPr%`#qU4YzdjW23k}mUS}W*-SeS|0 zVnCAN*MmF=l`U%$Qqgi}OI>BK#uRzyq0SIn1>3OWKH6G-uDX-8x;_QP>XBy0M_r4O z=}v{rg=hEc&t+8^i+^StZ71N(jG|A{{2`3-Z(R- zmU&1^r8Q})4fcpO>IeAEbm|7d4gJpf!$G!!h;X;5&Q9AJn-pd_hD2jX^FD6R|8l>h z3eIqj8lu3kq*Fh6LC`DI0N(4ehv+O^lKk$&_RTc{7OO>-;PBz*B-(E4{)8}?Po?Ml z{e(e)pfSR|OdIy(DHEsn5geW)JqaLY?sSQsrYou;(k->I=7lihER4CId}N30m|=sx zviVNk07D_b!BAei&w}4Nkg3>qN0XscMu-(Y3)*36>CC480{>Wt3`1u>6h_sQN7(*G z=MKRiR#l%QJBvs{>A>qKsp7@_W{5r10uIydIDtdT~MS!y-T_fF$tLk*Znh;Q_<^op*~Ne zBnofn*n?+QzW#=Gyy&{Eh}neZ?G`3-_V{Ql?fM6$fu?QZl}!KYG?H{~75eDwCz8vn zKM&>CMn+g}YAujF$7X7PfPq}YJ;hQk&1i)?y2`2|t#8<1MTu^9asl(P+m&--L)4|! zf3sx4pnXxs<*NzRfWx1B&q^ma2bzy|qjpUZ7?n--cwOII7w`1axLi0nS72;NdP;>W z{N^#zHUlO@9$PR@7H+Fy#h7&{-wAZImR4}CO$iXyV;wsNOWZ1`48TZ<4lx!?swB^;~n+elu zK3jxoEgXTAD{jH1$wYr49h6rZucDEe#z`FNb5-)@eObRXmNWX5ljG&hIswal6LEr7*|W9Gzf=gr zUslFTn@eVYRhhCC6{^vqQlwRkSrCj9%eJ7lahdSN3a}vi6hFCdENTfTEOuJJY&pcY ziXgy|Wj=y-9<~w$in|TblIdKzZEA{i^ckUAau|A17*T^{DKFX+8=}1*wSsgt@%vA4 zqm6wEYkzEEz1Ssjzbk2rp_nm`rH@w24%ubhP{j*4c`O2JEJ?ueW9sZL-8t3~@|C{- z`n1P;wc|Thm}!|FJ@iAeq2Y;+Y#zEUB0>SEh=uN6=M{so*#(r|nFK|u0hLkg^22wg zi`?iS`1)v`AyA@|-BWeX_$gNe67!Y*1qFo(kEJ?NSNO%jz@uu+R$22$0H3=FxPgt=0W$z#0Qq}%W zK-b^0)d0sud*9|LZd*%+Zo@CS34xM3F;_I&!4dANg2*J(?cZFE(*lxGV;`ML1!7h9 z$(F%ll-<24hPbcwK{NeSIgQ;<4^G?tsw}tQis01Ies8vjN@T~uE}(-!yBWi{8u;bC zgbPQHYMqwGVbpXB?KB<(SkjaB)}vs9Y$((5lAS#7H{{3>s_-zxBwfJ8CW5x{?c2_6 zcybs+5sge}O-hr)Z2gn4+K>BYNW{emHAAo9+Z&Nn%q)WK?^=7`{vcZ^!G+7LBu-Ch z4aGf&U8VLwn4{Z6Z2&LYO0_C3f)$Hr{bfmk#cBsDLxh-hXdACW_W9!(Qn=;A9e6a8 z#FnDAA&-4|mTa(a0^xegMU8$izCC~r*t*9PqUha9BrSRDOq*_cxOKrlCpbmV z8Md!NSQfs(E^6Mk64^E$*`KyRXugn6FPhu7hP0uz*vHn34osIPKC)Q;D#-^;d^#Z4 z*&Q%EKnT}!@pQRNT@-96$nmvwEI*9mjkZv#B^PSuC3+WwIq*&M7&zdU=IlhgsSE>Iq8u+O4WLw zsScMAj*TMfSZAA}pvySe>tTuR#alm#Hd}^S4|i5O*l&x2)by`vs_a+~c$1 z4b0(MkH?NHs}_xPZ%McC_?o*bMxgKQ*(WXF$d_p11?phCb?4ET9m(S3AiTr$&mUz| z7lcX{|HvmXRP#}AUWG4?Rtj1bkeE&-{i?bhoPLLww4!_(M+3z#4`0qt48ZaksfDf2 zWHI?q&2SB*AdE+E*GmkZnWpP9XKQ8d@3&zsbzd|gf_4QFYXyLfW`bzF2rk=q>B-c;9frt zBTs=K3&l{+DP#jncx7PXdse)4yr4D=NOlCeZin#(&(F=szrw1~UY;I=$8_glV zEd}iYnd|SzWHK1xi;aAx29RcN5mUb;xD`H0G7l9~rVVR(JIvFZWm|#W-Q+ZBUaiG# zwvH1mKo(^K5L)iSzcnGsIX;O!ld+mp4L4GIq(ccOo5&;i3`<2Fs4aWhxF0N4_s_vSLFKnhjdPb3nZ#he}CwV%dg~E&&A?l1t~b}@ok|66bam&7mPK~ zrg)}&czAUqw6Lc1A%FCqk9k6`rg%C!4ct_~EXvqnk)V2cp@`{BlaHKcf}3FM3|qv%>xRt>8JamhB|I0HG%=?VZ1l2mm~Su3=A=kjm)6gMB~elDA2 z<7cUj8S~XitcfqX_jWg8W*t*jM}1K?LOmI_XUd)qSgZ!^KlzV+o8I~(OrJ2ud2ku$ z7sf!X?9)3AAd$a*Cp0b7eJ~u>kxK?>wx7f2p$Mmo&H#K1U)X&5!$#ZmqYq_N0qx)( z_@NVUc0ZA2Vuw31?AW(^;O1H^6d0EyX!=#N5o4e#;jn*K@^QMYt8ZBi3KK^_C{NYC zZUhW`QFKNEirsnbSwA2nVG6094x4BIv5@~X37(bfQVaO-G*g@T(R;m$r+k8AM!TBu z=f80|AE=k$foP8;x9733B;d1~y~m46#+W^qGGN;};Zi@s3*0 zYbK(ea<$Bj@_yhaLb4XPXx6doxj4bH>Ad3m!kpvVPmmw#Ng&fEqa=YZ5hL_AHAbGK z$(2@;MIf+4fyeJG-a$RJWZD2M?jgInyN%V$;QZPt7gG8HN(ru(_R)cW9422Yr2piJ zKIvsa%1jsfM#|7i8?VLbwmag8(_%RMQQ-HZD5jfRPPM&=js;W9V{TUlQO2Ze{(+ln z*ed)xppY6ESl!#9HPQej{T>zv9-^9(1$5{r zZ@+^o13zU^TA~~&@cyPA$T>5OW?=75Dx5B}xK_W!XBBXrfjsF5$*moUNT~E~n@V0R zQr?o`z}2b-Di%5Wv8nY&qF4@Y?&W~d##d`4S{T(xp;T%OG24f-VIr)cI3qt;XzUg| z!dM$9BX3k}q^zS!e-2(&!Q!^e#Pn3|8oKNvajzxS^UV9)HjgRY%=H(txP=_bfVXEQ zaCM+x24#;wc6IQ3fw_L`@5A11g7DCh!^=xht~4li3D{e}&9XKtL)}RECp-S>eV@b_ zDm`h73Hh|ja1lyk5{Dekj(|V>vDH+JpcAV|tAgvj8{Dd5PiLL|k>^Uwa`_1iMR~uE z=-NY%-(T&KCdHO{^~-pMaItHD2DL!bv6S*XLX)~jV&#$*XgUA7BT8EXUd#aGvY;6z z?SqlicyW`l5j*maHBVxd0*zJkqNGFh(+T3^8Xg$0sd>uWzDLr^;{pc6(zbHz1-liM zpN|7x+r2lN>b?Nf98zGBkeY5HdTM$AbJ`#F%;VjObOAXDD`Bc4=RW3$pz8AvaEGeu zovUV^?R`` z?|1CxjO-Ar@YbHGHc=54CpqBY*yJV>|J%>8!+-5ug4=9M{>8(twHK1 zic(_Aw23YITZLtF*V!`HNaa!&)f2=B3eQK))*~IJW?Q06!w3qmgG@ zA(3SBe1!_%AB0fX-F;<_32~UFkKrzlI{?d6^D=@Rscb&mcggHz!55}>tg{1cw&dv$u3>IXw_9F+Ca)n*PMK*lLShoUg zNTmifhI@wI!#JvGvo<~)4FYlsGCYMt9Wd9r9hTM=oxRG$ds(%-Ri>nMwU2Ng?9+#YXth%EQomFpyDllC8#PP#7sA#!X zTN}%p_90aMc*wC^vBclsHerBn(?CFd$i%DJ8CNV({uVl$qg%hs z-J+}JfAnd&~fCEU6}i~MVKw;Pp$p!RXu<7o%E0LYtN=$~^{8Rs_? zOIiEJ6uW)xTw@L^aPnV?lgaj+cf1+4+y%Dn9Af!2X>}#`6_^4Ur1;tePDoMI)!TqVLRd$~-vh7r|F#mUI}8Zn z)hy|cr7T|Qi}7dXXvVhQa8&c5+_tLO8!?r20=BqLTli9m%!7f1`(d|88L*y+AvThr zD>PVr7}uNoB~~*?*YGwh;!l3ruf-R|EB;wa;zzsB-NXSx$R~GRYa1xU)dcY$cSs#Q z=!|_nN2H~u;irHGb(=RfMIxWUca&(W)~+tKN@^TJtWC>z z=Z6mdV3qxm97QvpG+s^KbLs|J_f8=Ee7Yw0rHmz2s=gxh0F4^lBw35tTi%_uBwx(< zyNW+8>=&xxdX$!>(j{?FYYbheX!^eUi~|`Qbc3pzu5+eo=`_5jmA zR^>Ki341B?5HZ^a_H+b6(DU%hu_61R>Kn9_s@rGh2xKJ8aGW)rd2=7fLJ-O>!-OHX z4)B(kPcvfz{LzJA!e4K%(q}&9GZXv=`sD{*EM4-exQC*Nl%Y9h{vF@WkkbzmEuy9P zhE(X&6|c*wN=9GLLW(Xy_jy$ z%fYOfrchYCzr?qiki?!2OR8noA7yldnei809nw_ zGZg+c_0O3BNqr{@wpV-a(+PNy6lleMVqJ#V{@ zR*w5{n9;YNpS-(>I~NT05GUv00%xC~Y6-3s7}5BY0m|f}T1bSVq^Q1QHp_t6Fqp|Bp zo8xF|mTKo5pf|;b-fef}?n~1yId&Tz=)>x}%FRAD764FTF*GAi^vcL|SO4 z(I`EgAx3QgHy}O{Xl5Xk?FCmf?*MKm+B{2Modoc8>Ye!4TfZ1RKKB>xN{vwmhG+Bj2)JYjN1rK4&#v=W3HS^MtLaF6uk zM$pY@=M5WcJ&Mj+1g_|`#fG!nKA>QH`>Q{3+Qwl+;^REkH3*ooIiM@IV8XZoQ$<)B zTSFHf)6zkxAfjyz^efge(s!C(@~h_tUN@#q;4!oBO%-nrM5X074{2pON5{i?a%9vrA{u<`=tWb7=9QV?1omi5_dJAAt-{U)zARFJ7}y~!K|CROw`$hsQi^*6_T z%2X+jO&m4d<@642z}FL@j)YfusD%R0u4|&Odj+am;a2@I+Vg7i;(M`XK6zaS?y13v zs#oIFy0*2PwsxCwy-`Rhz&}&RX|PgsD?apkSe>COkjqeSZ+0NI*r2ZZJJXu!D%dO# z(!nE{y87}6JO2~(LH&)EQQCGqu&E~{4lB_qp_fLTs$O68#zL~Z@^0oF##uMoea>CO zLJiuSp$I%7J*H>q6W6nX$qzVyE>Zj0#N`rW`JRA_a

    XnB%8-$9y-YLr2~%kBu6FAO#Z7(bmj%LZ_tr$sHV zl$3YWmC0{`na|l>ftaVloIGZELu3^gB!2*uKiDBOD|kfN$XomG1vx`bAW&4>n#;+h zr8XlhPxGh=hhLuotkTQ$EqwQTiXehy;A5@ff@MxQIuA*cYy%S)!!-woo($MKD&kSH z>J0BgTVcKB{zI#6pAP2ez|yMDO%`^k>?LW&bc-@={lcUC5ZIGv-fwcN|3E?}jX}1~ zl5|+Ed?vbiGj{X8|JTLA%k6~rjyn#x3ma&S8%{viXXj@G{Ixg~-60dG4q}5D63>PQ z)_~zBkMOs%_&XbDa4`2!#%wj6BVYAzjvAHRlIp-QiWOlrQxP2@}iZQ&=#`K7OZY*WN5`d^+fnfE-j`t?dsswI1R92shdV~4mqLIHl zfxoNax%H-0l@O^I6}d*vR~BPG79X6vZ6kSCCJ6z)<#;sZH8l zRmeYLtn=+lh*x9)Q}MCBI6n(&4wk~2>F0BEs@C(CCKV8_? z(4cMVmi=5tc+)8qV(k909-M$p#CWxm{Ee%&lor zMn+C`X`{_V#OH5HSiYlznkDr@FnT^BzI4$N249_ zXOcD#ff!)kz-b9p!6I6a6swe|M4;_zX&cOp6;L<)Rf^pIPQIzDbZN(*(oxgos0H&g z<4lMqX`&SZZ2I^90Z(E;kPa_pgsito?XerWXV}(_Z>!ypqO)P$iFF1VVj3*S>}M?Y zR&$s%(3N*vKuJ3SuG@G)ZP)Qlt6R5+su9_7!!cMl%8Wqxd^upcPbrbmRLErY;U9ym z>%YimGBeyTHk&g@Q{`dAMk-3-K)5rxB|HLa{z=7P)SB7|B1V-k68rj!=ExA>dfX~H zv=$Zhh}gLKb^kFjtJ20ByLK~djA7SRg%N0wNCQ1-=B{rVsg$Q^4(}8+p9F%x7>L_8 zyBDYu(vh7FY2s!8p=;5TZM-^g=zCIpXTwoJV)sG0z_VUzGY0Sh{F-}|1 z8^xh{x20-bCenKX7V*of5-i?5-IFr&fOQ;WM%^DZU&zt2L1)+e*83BLNSSVDC;Q!8 zMx=-d5B0KW3YD8SrRdTh-M?dU>!I*_1D?3t7qQN8Z`l0%+Rw8UJq@oKV7TXMLZl$= zOb{MKdcGu~hLd_%({-fON@YBfHBv{`n|UTb;Id`}sGT~;h zv!WokKmY-B6dc+_i5x*$!x7vo57Tq$h$Pd1QZDR#)z!^HbqE0CB{-$6?sH>VCyk6; z&Z%?%rq?}NxTD)bTCvs->mIvzXLjDPQ;W0BU!LkBS``|4=_C|FqnQcA8WZ;N|?6S2%A$8AMG;YbT$ zqUV_gYhZ9~L@l{05{;aW%&FklQ<~J)DsII;N(!VE6Ez*$Qqd zn(p9!Cm?ExN0E=01~^j#r^5rEe?*I-MH$tmPSzz#B@jZp`c*vF&wZW%2S8M?8W`l~ zC&$)^*u-L_Lyb2d6t5YMxdztGuaEV2{E8&p6&VHW(J;3)g^-Dp(O0KS$QQ=5U<9^x zAWY#Us~(a6N9Ss0TN?Wufi1o-><6gx#Pmle;Nl;CPZ%$AHQQnE zvYDgWO`{etMMd>-K6A;=T;=H{mT?MI!!Pwloba9?2<#tdLM zpNDsXBm+sKvtgMzM zJJ*kwlCkr#EjA*ikE!vPM9g`HsKDw0d3eJ#^Uf;6YDp2HZJ&Q>jz!oZYH zvTq6{{h@G83Jy(PhN-uuoeN10Ai8qOz0Kc@GyUrH!`=uiDEoIg-a}AWo5t){wefw+ zy@=h;juV+1i+_=@h56Y#AsVWoYv^>;1XD}phevpsFC$Sw zq?Xo{+|SXs-UnQxzW1f+8e##JI=LE2+D|_wgVJNL3X3|o#4-j5gmYV|_q4H-Js8E4 zZaFKVEhMVBF%0QS={R?Mox#hX5tJn!!0NuP_F;kmL<>x9(~=UA;@kk6C{c!a$+B_s zsb8ykKdUwj0J`&nQ71z}XqH&~7yhe>@!M_Wfbto%zR8z5OW5nX)0woV3P~Ba>WT5m zH7v1l|bG}xni6%!&^S2Ag?uBevAMwmxJLjkEs%~ z)Hw9oudg_JuivcOsFM0eHAg`9SEr-`mkTUXm z?9HaHI|jJtxh*hIR>yWM^Tx-9?dEvf45k*zj0y zjA0OqcyYSDhPHtxyhjeY`{E&ShCYR?EBS?ccv#E_yF6{@)WYOU-OchTq+4!3L_>Fs z=w3)_x)`lk5k~t33KG4sDURNI4(szpZcQc`!9cy`y6)peAU|-vJ{TED8tB9Rn|u}D=6S`CNin3t(7gz)_l_9DhtK;3FO_2b4-I~heJRUWt1|S+(;7x zqq@i@hCXj`OLsHSzQ7nz;t!cr61N!IEWt3>-+YfiLKtN#m4e>7hCaZ(u%e+vE=jhH zC0CObu}K5=nHYuZYGr3d6yH>DTkb$Y2|WtcE&2dtLydH^J~*hW0xTLI7e^Q5!?lc! z9d3FM++FOcTyUBmT+hhR&w;3#V@dYqmGKs00}r*sr_V=zJYNw08E)h7S&v|47+pYj zFPO)7HHz`P2{dLBG8VTQ#Tx|}eq5;GUIzRVwT}dnE{rYo6--WVI83mxoF{g8mdd3U zAl1@G;Y=^*zc?6Q4OBcaA%P*pz~JoRE_BBjn?bArenFp@JfBZjg!^O|oF1cPMO(2!lTvFEZO1BU%|4=&G#LM1RYQIa+dKFCn z_|(Lvrg%gM_l@G-sTG)J7>8=n0iseB9kN493CpCCfp&j>6{RHuE2mUfdA zz0CRmM3oOd7v85Pa&Wjj$dDtonx$M~R2zHcT+3UzK@qabSuAzbK!a*1l> z@8A?L_-?yw^`M#Njf>u1h8YQ4RLG6#d%ftD83jIcme~X)dyPW%L|FbQlZKuc=Rq4B zV1k)c{B(7GrA+vOUN=pNyLWJO4wNor9A9!Mh1!YZ?_Nr;=yc1K_R0`7yojtDDapG@#Mw0_C#w*H?rEx z^%rNx?%#bHpT(wXFjd9t{P!vtZx3&bv+dm7Lje}ZhvyIE3Ix_Vcye~U6qavs|G|1% zItkXnUsK`#Klk4hwv&={$a|^8e<4i+W9y|H=P4H_Ie`b@d*)%dvqz&k_Nf=4&Bil;h=n4*?}PvnE2+g^MA*ZJ>{`nvCx>=4F9dK2>q#=qiQBUwSvQEv5!Br`lQ+R_|Nv{&34v;v8t!n-`Y$>e%*^U0OIH+`_MJ*Cq4*dw;= zinz7NGDFAo4a*p7$FizC#5q7Jq7?C62zWE!9@s)!_<=6ftl6=4@l7I^uTckr6Y?~d z|8V>=kg7lD#zAcMXH~HMLKp{T;`|-;46+$T{8I#jxknY^+pun@VKOgr*JwSmt$^<^ z5&{bBVD!b(-m44UP}*2gPimRbg=b9VB|%rIMYgWNFQyUZwn<|_q+O_ZWFFFoIKW1d3@I`jVJW4axI@DVs=CboGom7n-X&V<-KO1s>yN(FuJQ=!saW^Mv|1!gwF+ opmiKhytrv(Khb=y*jFeuqPAq_Ew(B5^`m7YS8yppi5mI;0R%c&EC2ui literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xcc.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xcc.mq5 new file mode 100644 index 0000000..2f45b84 --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xcc.mq5 @@ -0,0 +1,437 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Candle Styles +// --------------------------------------------------- +// Name: X121 XCC +// Description: Candle Styles ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCC Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121 XCC" + +// +// Holds an SnapShot of Charts Configuration ... +struct XChartStyle +{ + // + // chart's ID ... + long chartId; + // + // chart's mode ... + ENUM_CHART_MODE mode; + // + // show bid line ... + bool showBidLine; + // + // show ask line ... + bool showAskLine; + // + // show grids on chart ... + bool showGrid; + // + // show volumes ... + bool showVolumes; + // + // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) ... + bool showTradeLevels; + // + // chart autoscroll ... + bool autoScroll; + // + // chart quick navigation state ... + bool quickNavigation; + // + // chart's foreground color ... + color foreGroundColor; + // + // chart's background color ... + color backGroundColor; + // + // Up Color ... + color upColor; + // + // Down Color ... + color downColor; + // + // Bullish color ... + color bullishColor; + // + // Bearish color ... + color bearishColor; + // + // grid color ... + color gridColor; + // + // bid line color ... + color bidLineColor; + // + // ask line color ... + color askLineColor; + // + // line mode and doji candlestick color ... + color lineColor; + // + // Color of stop order levels (Stop Loss and Take Profit) ... + color stopColor; + // + // volumes color ... + color volumesColor; +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Chart Style"; +input ENUM_CHART_MODE mode = CHART_CANDLES; // Mode +input color upColor = clrGreen; // Up Color +input color downColor = clrRed; // Down Color +input color lineColor = clrGreen; // Line mode and Doji candlestick Color +input color bullishColor = clrGreen; // Bullish Color +input color bearishColor = clrRed; // Bearish Color +input color volumesColor = clrGreen; // Volumes Color + +// +input group "Presentation"; +input bool showCandles = true; // Show Candles + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Draw Library ... +#include "../Libraries/x-saherelm.draw.lib.mq5" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +XChartStyle chartStyle; +XChartStyle clearStyle; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + drawPrefix = ShortName; + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Apply Chart Style ... + ApplyCustomChartStyle(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // this counts Available Bars ... + int limit; + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// Apply Custom Chart Style ... +void ApplyCustomChartStyle() +{ + // + // Read Current Chart Config and Store it ... + ReadChartStyle(); + + // + // After Reading Current Chart Style ... + // we have to Save Configs and Change Styles ... + clearStyle = chartStyle; + + // + clearStyle.upColor = CLR_NONE; + clearStyle.downColor = CLR_NONE; + clearStyle.lineColor = CLR_NONE; + clearStyle.bullishColor = CLR_NONE; + clearStyle.bearishColor = CLR_NONE; + + // + // Decide to Show or not Candles based on User Input ... + if (showCandles) + { + SetChartStyle(chartStyle); + } + else + { + SetChartStyle(clearStyle); + } +} + +// +// Read Previous Chart Style ... +void ReadChartStyle() +{ + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + chartStyle.chartId = chartId; + + // + // Retrieve Chart Mode ... + chartStyle.mode = (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); + + // + chartStyle.showBidLine = (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); + chartStyle.showAskLine = (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); + chartStyle.showGrid = (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); + chartStyle.showVolumes = (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); + chartStyle.showTradeLevels = (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); + chartStyle.autoScroll = (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); + chartStyle.quickNavigation = (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); + + // + chartStyle.foreGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); + chartStyle.backGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); + chartStyle.upColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); + chartStyle.downColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); + chartStyle.bullishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); + chartStyle.bearishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); + chartStyle.gridColor = (color)ChartGetInteger(chartId, CHART_COLOR_GRID); + chartStyle.bidLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_BID); + chartStyle.askLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_ASK); + chartStyle.stopColor = (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); + chartStyle.lineColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); + chartStyle.volumesColor = (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); + + // + chartStyle.mode = mode; + chartStyle.upColor = upColor; + chartStyle.downColor = downColor; + chartStyle.lineColor = lineColor; + chartStyle.bearishColor = bearishColor; + chartStyle.bullishColor = bullishColor; + chartStyle.volumesColor = volumesColor; +} + +// +// Set Chart Style ... +void SetChartStyle( + XChartStyle &mChartStyle // Chart Style to Apply +) +{ + // + ApplyChartStyle( + mChartStyle.chartId, + mChartStyle.mode, + mChartStyle.showBidLine, + mChartStyle.showAskLine, + mChartStyle.showGrid, + mChartStyle.showVolumes, + mChartStyle.showTradeLevels, + mChartStyle.autoScroll, + mChartStyle.quickNavigation, + mChartStyle.foreGroundColor, + mChartStyle.backGroundColor, + mChartStyle.upColor, + mChartStyle.downColor, + mChartStyle.bullishColor, + mChartStyle.bearishColor, + mChartStyle.gridColor, + mChartStyle.bidLineColor, + mChartStyle.askLineColor, + mChartStyle.lineColor, + mChartStyle.stopColor, + mChartStyle.volumesColor); +} + +// +// END Functions ... +// diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xche.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xche.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..6dbf4f7f8e7d4597b08c90dd4d65c8b5f6626099 GIT binary patch literal 19300 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 CeR^L2 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xche.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xche.mq5 new file mode 100644 index 0000000..d8ed104 --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xche.mq5 @@ -0,0 +1,624 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XCHE +// Description: XCHE ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCHE Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XCHE" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; +input int cheLength = 35; // Length +input int cheLoopback = 26; // Loopback +input double cheMultiplier1 = 3.0; // 1st Multiplier +input double cheMultiplier2 = 3.5; // 2nd Multiplier +input ENUM_APPLIED_PRICE cheUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied to +input ENUM_APPLIED_PRICE cheLowerAppliedTo = PRICE_LOW; // Lower Zone Applied to + +// +input group "Presentation"; + +// +input int cheArrowCode = 159; // CHE Arrow Code + +// +input bool showLE1 = true; // Show 1st Long Exit +input bool showSE1 = true; // Show 1st Short Exit +input bool showLE2 = true; // Show 2st Long Exit +input bool showSE2 = true; // Show 2st Short Exit + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 8 + +// +// Exit 1 ... + +// +// LONG ... + +// +#define le1BufferIndex 0 +double le1Buffer[]; + +#property indicator_label1 "X121 LE1" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrAqua +#property indicator_style1 STYLE_DOT +#property indicator_width1 1 + +// +// SHORT ... + +// +#define se1BufferIndex 1 +double se1Buffer[]; + +#property indicator_label2 "X121 SE1" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrMagenta +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +// +// Exit 2 ... + +// +// LONG ... + +// +#define le2BufferIndex 2 +double le2Buffer[]; + +#property indicator_label3 "X121 LE2" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrAqua +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +// +// SHORT ... + +// +#define se2BufferIndex 3 +double se2Buffer[]; + +#property indicator_label4 "X121 SE2" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrMagenta +#property indicator_style4 STYLE_SOLID +#property indicator_width4 1 + +// +// Start Buffers ... + +// +#define le1StartBufferIndex 4 +double le1StartBuffer[]; + +// +#property indicator_label5 "X121 LE1 S" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrLime + +// +#define se1StartBufferIndex 5 +double se1StartBuffer[]; + +// +#property indicator_label6 "X121 SE1 S" +#property indicator_type6 DRAW_ARROW +#property indicator_color6 clrRed + +// +#define le2StartBufferIndex 6 +double le2StartBuffer[]; + +// +#property indicator_label7 "X121 LE2 S" +#property indicator_type7 DRAW_ARROW +#property indicator_color7 clrLime + +// +#define se2StartBufferIndex 7 +double se2StartBuffer[]; + +// +#property indicator_label8 "X121 SE2 S" +#property indicator_type8 DRAW_ARROW +#property indicator_color8 clrRed + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// Working Array ... +double work[][6]; +#define hi1Idx 0 +#define lo1Idx 1 +#define hi2Idx 2 +#define lo2Idx 3 +#define trend1Idx 4 +#define trend2Idx 5 + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input cheLength, here we get max Input cheLength + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + if (Bars(_Symbol, _Period) < rates_total) + { + return (prev_calculated); + } + + // + if (ArrayRange(work, 0) != rates_total) + { + ArrayResize(work, rates_total); + } + + // + // this counts Available Bars ... + + // + limit = prev_calculated - 1; + if (limit < 0) + { + limit = 0; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + low, + close); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = true; + + // + result = + cheLength >= 9 && + cheLoopback >= 0; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(cheLength, cheLoopback); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // LEVEL 1 ... + + // + // Long Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE le1DrawType = showLE1 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE le1StartDrawType = showLE1 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(le1BufferIndex, le1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(le1BufferIndex, PLOT_SHOW_DATA, showLE1); + PlotIndexSetInteger(le1BufferIndex, PLOT_DRAW_TYPE, le1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(le1StartBufferIndex, le1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_DRAW_TYPE, le1StartDrawType); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // Short Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE se1DrawType = showSE1 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE se1StartDrawType = showSE1 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(se1BufferIndex, se1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(se1BufferIndex, PLOT_SHOW_DATA, showSE1); + PlotIndexSetInteger(se1BufferIndex, PLOT_DRAW_TYPE, se1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(se1StartBufferIndex, se1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_DRAW_TYPE, se1StartDrawType); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // LEVEL 2 ... + + // + // Long Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE le2DrawType = showLE2 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE le2StartDrawType = showLE2 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(le2BufferIndex, le2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(le2BufferIndex, PLOT_SHOW_DATA, showLE2); + PlotIndexSetInteger(le2BufferIndex, PLOT_DRAW_TYPE, le2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(le2StartBufferIndex, le2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_DRAW_TYPE, le2StartDrawType); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // Short Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE se2DrawType = showSE2 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE se2StartDrawType = showSE2 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(se2BufferIndex, se2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(se2BufferIndex, PLOT_SHOW_DATA, showSE2); + PlotIndexSetInteger(se2BufferIndex, PLOT_DRAW_TYPE, se2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(se2StartBufferIndex, se2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_DRAW_TYPE, se2StartDrawType); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_ARROW, cheArrowCode); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Buffers ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + int prevCalculated, // Previous Calculated + int ratesTotal, // Total Rates + const double &open[], // Rates Open ... + const double &high[], // Rates High ... + const double &low[], // Rates Low ... + const double &close[] // Rates Close ... +) +{ + // + // Cleanup Buffers ... + le1Buffer[bar_index] = le1StartBuffer[bar_index] = se1Buffer[bar_index] = se1StartBuffer[bar_index] = EMPTY_VALUE; + le2Buffer[bar_index] = le2StartBuffer[bar_index] = se2Buffer[bar_index] = se2StartBuffer[bar_index] = EMPTY_VALUE; + + // + int start = MathMax(bar_index - cheLoopback, 0); + + // + // Calculate ATR Value ... + double atrValue = 0; + for (int k = 1; k <= cheLength && (bar_index - k - 1) >= 0; k++) + { + // + atrValue += MathMax(high[bar_index - k], close[MathMax(bar_index - k - 1, 0)]) - + MathMin(low[bar_index - k], close[MathMax(bar_index - k - 1, 0)]); + } + atrValue /= (double)cheLength; + + // + // Retrieve Highest High and Lowest Lows ... + double cheLoopbackMax = high[ArrayMaximum(high, start, cheLoopback)]; + double cheLoopbackMin = low[ArrayMinimum(low, start, cheLoopback)]; + + // + // Fill Multi Dimesional Working Array ... + work[bar_index][hi1Idx] = cheLoopbackMax - cheMultiplier1 * atrValue; + work[bar_index][lo1Idx] = cheLoopbackMin + cheMultiplier1 * atrValue; + work[bar_index][hi2Idx] = cheLoopbackMax - cheMultiplier2 * atrValue; + work[bar_index][lo2Idx] = cheLoopbackMin + cheMultiplier2 * atrValue; + work[bar_index][trend1Idx] = (bar_index > 0) ? work[bar_index - 1][trend1Idx] : 0; + work[bar_index][trend2Idx] = (bar_index > 0) ? work[bar_index - 1][trend2Idx] : 0; + + // + if (bar_index > 0) + { + // + // Calculate Trends ... + if (close[bar_index] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][trend1Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][trend1Idx] = -1; + } + + // + if (close[bar_index] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][trend2Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][trend2Idx] = -1; + } + + // + // Calculate Exit Values ... + + // + // Exit 1 ... + + // + // Long ... + if (cheMultiplier1 > 0 && work[bar_index][trend1Idx] == 1) + { + // + if (work[bar_index][hi1Idx] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][hi1Idx] = work[bar_index - 1][hi1Idx]; + } + + // + le1Buffer[bar_index] = work[bar_index][hi1Idx]; + + // + if (le1Buffer[bar_index - 1] == EMPTY_VALUE) + { + le1StartBuffer[bar_index] = le1Buffer[bar_index]; + } + } + + // + // Short ... + if (cheMultiplier1 > 0 && work[bar_index][trend1Idx] == -1) + { + // + if (work[bar_index][lo1Idx] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][lo1Idx] = work[bar_index - 1][lo1Idx]; + } + + // + se1Buffer[bar_index] = work[bar_index][lo1Idx]; + + // + if (se1Buffer[bar_index - 1] == EMPTY_VALUE) + { + se1StartBuffer[bar_index] = se1Buffer[bar_index]; + } + } + + // + // Exit 2 ... + + // + // Long ... + if (cheMultiplier2 > 0 && work[bar_index][trend2Idx] == 1) + { + if (work[bar_index][hi2Idx] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][hi2Idx] = work[bar_index - 1][hi2Idx]; + } + + // + le2Buffer[bar_index] = work[bar_index][hi2Idx]; + + // + if (le2Buffer[bar_index - 1] == EMPTY_VALUE) + { + le2StartBuffer[bar_index] = le2Buffer[bar_index]; + } + } + + // + // Short ... + if (cheMultiplier2 > 0 && work[bar_index][trend2Idx] == -1) + { + // + if (work[bar_index][lo2Idx] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][lo2Idx] = work[bar_index - 1][lo2Idx]; + } + + // + se2Buffer[bar_index] = work[bar_index][lo2Idx]; + + // + if (se2Buffer[bar_index - 1] == EMPTY_VALUE) + { + se2StartBuffer[bar_index] = se2Buffer[bar_index]; + } + } + } +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xct.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xct.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..eb6cc3b46bd842db14b7eea6ec1552467d67a15a GIT binary patch literal 16810 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

    L^35w*i_V0hEwJuU;`0k3dsW!_?MshnfZe! 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 Jf8F+~{};OOK%D>p literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xct.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xct.mq5 new file mode 100644 index 0000000..286882a --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xct.mq5 @@ -0,0 +1,262 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121 XCT +// Description: Trend Magic Indicator ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCT Indicator" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "X121 XCT" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input int fontSize = 15; // Font Size +input string font = "Arial"; // Font +input color clr = clrYellow; // Text Color +input ENUM_BASE_CORNER corner = CORNER_RIGHT_LOWER; // Text Position + +// +input group "Presentation"; +input bool showTimer = true; // Show Candle Time + +// +// END Inputs ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +bool isCreatedObject; +string tag; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + + // + tag = ShortName + _Symbol + ToString(_Period); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Delete Object ... + ObjectDelete(0, tag); + + // + Comment(""); +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + if (!showTimer) + { + return rates_total; + } + + // + XBarRemainsTime barRemains; + barRemains.Init( + _Symbol, + _Period + // + ); + + // + string msg = barRemains + .ToString( + "", + "", + "", + "", + "", + ":", + true + // + ); + + // + long mSpread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD); + + // + string _sp = ""; + if (mSpread < 10) + _sp = ".."; + else if (mSpread < 100) + _sp = "."; + + // + string objText = "Spread: " + IntegerToString(mSpread) + _sp + ", Next Bar in: " + msg; + + // + if (IsValid(tag) && !isCreatedObject) + { + CreateIndicatorObject(); + } + + // + if (isCreatedObject) + { + ObjectSetString(0, tag, OBJPROP_TEXT, objText); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +void CreateIndicatorObject() +{ + // + if (!showTimer || + !IsValid(tag)) + { + return; + } + + // + isCreatedObject = ObjectCreate(0, tag, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, tag, OBJPROP_CORNER, corner); + ObjectSetInteger(0, tag, OBJPROP_XDISTANCE, 10); + ObjectSetInteger(0, tag, OBJPROP_YDISTANCE, 2); + + // + ENUM_ANCHOR_POINT Anchor = ANCHOR_LEFT_UPPER; + switch (corner) + { + case CORNER_LEFT_UPPER: + Anchor = ANCHOR_LEFT_UPPER; + break; + case CORNER_RIGHT_UPPER: + Anchor = ANCHOR_RIGHT_UPPER; + break; + case CORNER_LEFT_LOWER: + Anchor = ANCHOR_LEFT_LOWER; + break; + case CORNER_RIGHT_LOWER: + Anchor = ANCHOR_RIGHT_LOWER; + break; + } + + // + int mFontSize = fontSize > 0 + ? fontSize + : 10; + + // + string mFont = IsValid(font) + ? font + : "Arial"; + + // + ObjectSetString(0, tag, OBJPROP_FONT, mFont); + ObjectSetInteger(0, tag, OBJPROP_COLOR, clr); + ObjectSetInteger(0, tag, OBJPROP_ANCHOR, Anchor); + ObjectSetInteger(0, tag, OBJPROP_FONTSIZE, mFontSize); +} + +// +// END Functions ... +// diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xdon.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xdon.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..979c4c11fe72b8b915c79f8f7c24bf659e03d5f1 GIT binary patch literal 15592 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 kL6SS8QSKyhiY!?RdQ12Q!B<9s zJSXYL=tVL$t4z>>gB9(o3#xoDAj`p1sB((d=7&PaO|_r{OK;odfG=J?wDaCAg&G%= z_@~&e*%11a3&>ZX)%U^2K!YV~sulK=Q zmN(EE_S@3x?vu&*f8vmav&ONHkKT(&*REqMqR(A?!Xh2Z^;~4-yk#}HO{R?6!TEnZ zYfbf~gnrFRfsj%h^4eKGJmS za%S;Oq}Nza?!)CFj{1?n&}hi6PWfXY=1^I!V%O4yeSTa#f^B-~_qgDW;88D4B;TIlGeJV$d>T}WR%w{Vaz_&+ze?&&1&Dt3p7K{c8oVa?M5L2_e~z3Dbdc$I z;2Zk=28GmIc-Zga_iGs?P9B7XTVPzddFQBZpy|%qo%hL(ZS@1Jk6dGSibQm!=}M*6 z5wkQC&yosJwf?e+M3cCr3YiF<7SC9KUBl2sBMvG92&Cz%l6d67JsRE)KOK6snp#f_ zcF4nKO!)S8|8Mt84(KOKf{zC$Bjys^XZn^`OKc(3AN7yu+q}bVi^Q rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + donchainLength > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + // + // Open ... + + // + // UPPER ... + bool canShowCOpenUpper = showUpper && showOpen; + ENUM_DRAW_TYPE donOpenUpperDrawType = canShowCOpenUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenUpperBuffer, true); + SetIndexBuffer(donOpenUpperBufferIndex, donOpenUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenUpper); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_DRAW_TYPE, donOpenUpperDrawType); + + // + // LOWER ... + bool canShowCOpenLower = showLower && showOpen; + ENUM_DRAW_TYPE donOpenLowerDrawType = canShowCOpenLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenLowerBuffer, true); + SetIndexBuffer(donOpenLowerBufferIndex, donOpenLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenLower); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_DRAW_TYPE, donOpenLowerDrawType); + + // + // Close ... + + // + // UPPER ... + bool canShowCCloseUpper = showUpper && showClose; + ENUM_DRAW_TYPE donCloseUpperDrawType = canShowCCloseUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseUpperBuffer, true); + SetIndexBuffer(donCloseUpperBufferIndex, donCloseUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseUpper); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_DRAW_TYPE, donCloseUpperDrawType); + + // + // LOWER ... + bool canShowCCloseLower = showLower && showClose; + ENUM_DRAW_TYPE donCloseLowerDrawType = canShowCCloseLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseLowerBuffer, true); + SetIndexBuffer(donCloseLowerBufferIndex, donCloseLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseLower); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_DRAW_TYPE, donCloseLowerDrawType); + + // + // High ... + + // + // UPPER ... + bool canShowCHighUpper = showUpper && showHigh; + ENUM_DRAW_TYPE donHighUpperDrawType = canShowCHighUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighUpperBuffer, true); + SetIndexBuffer(donHighUpperBufferIndex, donHighUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighUpper); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_DRAW_TYPE, donHighUpperDrawType); + + // + // LOWER ... + bool canShowCHighLower = showLower && showHigh; + ENUM_DRAW_TYPE donHighLowerDrawType = canShowCHighLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighLowerBuffer, true); + SetIndexBuffer(donHighLowerBufferIndex, donHighLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighLower); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_DRAW_TYPE, donHighLowerDrawType); + + // + // Low ... + + // + // UPPER ... + bool canShowCLowUpper = showUpper && showLow; + ENUM_DRAW_TYPE donLowUpperDrawType = canShowCLowUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowUpperBuffer, true); + SetIndexBuffer(donLowUpperBufferIndex, donLowUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowUpper); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_DRAW_TYPE, donLowUpperDrawType); + + // + // LOWER ... + bool canShowCLowLower = showLower && showLow; + ENUM_DRAW_TYPE donLowLowerDrawType = canShowCLowLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowLowerBuffer, true); + SetIndexBuffer(donLowLowerBufferIndex, donLowLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowLower); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_DRAW_TYPE, donLowLowerDrawType); + + // + // Data Buffers ... +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateDonchains( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + donOpenUpperBuffer[barIndex] = EMPTY_VALUE; + donOpenLowerBuffer[barIndex] = EMPTY_VALUE; + donCloseUpperBuffer[barIndex] = EMPTY_VALUE; + donCloseLowerBuffer[barIndex] = EMPTY_VALUE; + donHighUpperBuffer[barIndex] = EMPTY_VALUE; + donHighLowerBuffer[barIndex] = EMPTY_VALUE; + donLowUpperBuffer[barIndex] = EMPTY_VALUE; + donLowLowerBuffer[barIndex] = EMPTY_VALUE; +} + +/** + * Calculate Donchain ... + * + * @param bar_index: Integer, Bar Index ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Donchain Length ... + * @param _ouBuffer: Double Array Reference ... + * @param _olBuffer: Double Array Reference ... + * @param _huBuffer: Double Array Reference ... + * @param _hlBuffer: Double Array Reference ... + * @param _luBuffer: Double Array Reference ... + * @param _llBuffer: Double Array Reference ... + * @param _cuBuffer: Double Array Reference ... + * @param _clBuffer: Double Array Reference ... + */ +void CalculateDonchain( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + // + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, + // + double &_ouBuffer[], + double &_olBuffer[], + double &_huBuffer[], + double &_hlBuffer[], + double &_luBuffer[], + double &_llBuffer[], + double &_cuBuffer[], + double &_clBuffer[] // +) +{ + // + double iUpper = 0; + double iLower = 0; + + // + // OPEN ... + + // + int from = bar_index; + + // + iUpper = open[ArrayMaximum(open, from, _length)]; + iLower = open[ArrayMinimum(open, from, _length)]; + + // + _ouBuffer[bar_index] = iUpper; + _olBuffer[bar_index] = iLower; + + // + // HIGH ... + + // + iUpper = high[ArrayMaximum(high, from, _length)]; + iLower = high[ArrayMinimum(high, from, _length)]; + + // + _huBuffer[bar_index] = iUpper; + _hlBuffer[bar_index] = iLower; + + // + // LOW ... + + // + iUpper = low[ArrayMaximum(low, from, _length)]; + iLower = low[ArrayMinimum(low, from, _length)]; + + // + _luBuffer[bar_index] = iUpper; + _llBuffer[bar_index] = iLower; + + // + // CLOSE ... + + // + iUpper = close[ArrayMaximum(close, from, _length)]; + iLower = close[ArrayMinimum(close, from, _length)]; + + // + _cuBuffer[bar_index] = iUpper; + _clBuffer[bar_index] = iLower; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateDonchains( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateDonchain( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume, + // + donchainLength, + // + donOpenUpperBuffer, + donOpenLowerBuffer, + donHighUpperBuffer, + donHighLowerBuffer, + donLowUpperBuffer, + donLowLowerBuffer, + donCloseUpperBuffer, + donCloseLowerBuffer // + ); +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xhk.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xhk.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..e5c2bd3dfa393e51abcac7693455953023be0dd7 GIT binary patch literal 17042 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

    dsQO0K(LF@VQJY%dpKejGpsEQ@Pko6^&GZ#)Y} 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 w%Er rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + true + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(0, xhkSmoothingLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + + // + // RAW ... + + // + // Raw Candles Color ... + ArraySetAsSeries(rawHKColorBuffer, true); + SetIndexBuffer(rawHKColorBufferIndex, rawHKColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Set EMPTY_VALUE on Candles Buffer ... + PlotIndexSetDouble(rawHKBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(rawHKBufferIndex, PLOT_SHOW_DATA, false); + + // + // Open ... + ArraySetAsSeries(openHKBuffer, true); + SetIndexBuffer(openHKBufferIndex, openHKBuffer, INDICATOR_DATA); + + // + // High ... + ArraySetAsSeries(highHKBuffer, true); + SetIndexBuffer(highHKBufferIndex, highHKBuffer, INDICATOR_DATA); + + // + // Close ... + ArraySetAsSeries(closeHKBuffer, true); + SetIndexBuffer(closeHKBufferIndex, closeHKBuffer, INDICATOR_DATA); + + // + // Low ... + ArraySetAsSeries(lowHKBuffer, true); + SetIndexBuffer(lowHKBufferIndex, lowHKBuffer, INDICATOR_DATA); + + // + // SMOOTHED ... + + // + // Candles Color ... + ArraySetAsSeries(candleColorBuffer, true); + SetIndexBuffer(candleColorBufferIndex, candleColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Set EMPTY_VALUE on Candles Buffer ... + PlotIndexSetDouble(candlesBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(candlesBufferIndex, PLOT_SHOW_DATA, false); + + // + // Open ... + ArraySetAsSeries(openBuffer, true); + SetIndexBuffer(openBufferIndex, openBuffer, INDICATOR_DATA); + + // + // High ... + ArraySetAsSeries(highBuffer, true); + SetIndexBuffer(highBufferIndex, highBuffer, INDICATOR_DATA); + + // + // Close ... + ArraySetAsSeries(closeBuffer, true); + SetIndexBuffer(closeBufferIndex, closeBuffer, INDICATOR_DATA); + + // + // Low ... + ArraySetAsSeries(lowBuffer, true); + SetIndexBuffer(lowBufferIndex, lowBuffer, INDICATOR_DATA); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateXHK( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + lowHKBuffer[barIndex] = 0.0; + openHKBuffer[barIndex] = 0.0; + highHKBuffer[barIndex] = 0.0; + closeHKBuffer[barIndex] = 0.0; + rawHKColorBuffer[barIndex] = hideColorIDX; + + // + lowBuffer[barIndex] = 0.0; + openBuffer[barIndex] = 0.0; + highBuffer[barIndex] = 0.0; + closeBuffer[barIndex] = 0.0; + candleColorBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate ATR Zones ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateXHK( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + double mPrevHKOpenValue; + double mPrevHKCloseValue; + + // + if (ArraySize(open) <= bar_index + 1) + { + // + mPrevHKOpenValue = 0; + mPrevHKCloseValue = 0; + } + else + { + // + mPrevHKOpenValue = openHKBuffer[bar_index + 1]; + mPrevHKCloseValue = closeHKBuffer[bar_index + 1]; + } + + // + double mHKOpenValue = (mPrevHKOpenValue + mPrevHKCloseValue) / 2; + double mHKCloseValue = (open[bar_index] + high[bar_index] + close[bar_index] + low[bar_index]) / 4; + double mHKHighValue = MathMax(high[bar_index], MathMax(mHKOpenValue, mHKCloseValue)); + double mHKLowValue = MathMin(low[bar_index], MathMin(mHKOpenValue, mHKCloseValue)); + + // + double candleColorValue = + mHKOpenValue < mHKCloseValue ? bullishColorIDX : bearishColorIDX; + + // + // Raw HK Buffers ... + openHKBuffer[bar_index] = mHKOpenValue; + highHKBuffer[bar_index] = mHKHighValue; + lowHKBuffer[bar_index] = mHKLowValue; + closeHKBuffer[bar_index] = mHKCloseValue; + rawHKColorBuffer[bar_index] = drawRawXHKCandles ? candleColorValue : hideColorIDX; + + // + // Apply Smoothing ... + bool canSmooth = xhkSmoothingLength > 0 && + xhkSmoothingMode != X_MA_MODE_NONE; + if (!canSmooth) + { + // + double min = MathMin(mHKOpenValue, mHKCloseValue); + double max = MathMax(mHKOpenValue, mHKCloseValue); + + // + openBuffer[bar_index] = mHKOpenValue; + highBuffer[bar_index] = xhkIgnoreSmoothingShadows ? max : mHKHighValue; + lowBuffer[bar_index] = xhkIgnoreSmoothingShadows ? min : mHKLowValue; + closeBuffer[bar_index] = mHKCloseValue; + candleColorBuffer[bar_index] = drawSmoothedXHKCandles ? candleColorValue : hideColorIDX; + } + else + { + // + // Open ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + xhkSmoothingLength, + openHKBuffer, + openBuffer, + xhkSmoothingMode // + ); + + // + // Close ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + xhkSmoothingLength, + closeHKBuffer, + closeBuffer, + xhkSmoothingMode // + ); + + // + // Ignoring Shadows ... + if (!xhkIgnoreSmoothingShadows) + { + // + // High ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + xhkSmoothingLength, + highHKBuffer, + highBuffer, + xhkSmoothingMode // + ); + + // + // Low ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + xhkSmoothingLength, + lowHKBuffer, + lowBuffer, + xhkSmoothingMode // + ); + } + else + { + // + double min = MathMin(closeBuffer[bar_index], openBuffer[bar_index]); + double max = MathMin(closeBuffer[bar_index], openBuffer[bar_index]); + + // + lowBuffer[bar_index] = min; + highBuffer[bar_index] = max; + } + + // + // Calculate Smoothed Color ... + candleColorValue = + openBuffer[bar_index] < closeBuffer[bar_index] ? bullishColorIDX : bearishColorIDX; + candleColorBuffer[bar_index] = drawSmoothedXHKCandles ? candleColorValue : hideColorIDX; + } +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xpv.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xpv.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..32d3afbfea05d357fb67cba828aa618b33fd9ffe GIT binary patch literal 43024 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 Ih1 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 TQE0py=Ifg}H0k~@fl~i}C5%$$ literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xpv.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xpv.mq5 new file mode 100644 index 0000000..0af0a37 --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xpv.mq5 @@ -0,0 +1,1074 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XPV +// Description: XPV ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XPV Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XPV" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; + +// +input group "Short"; +input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES scPeriod = NULL; // Time Period + +// +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES mcPeriod = NULL; // Time Period + +// +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES lcPeriod = NULL; // Time Period + +// +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES hcPeriod = NULL; // Time Period + +// +input group "Boundary Detection"; +input ENUM_SERIESMODE hhMode = MODE_HIGH; // Highest High Calculation Method +input ENUM_SERIESMODE llMode = MODE_LOW; // Lowest Low Calculation Method +input ENUM_X_FIBO_LEVELS goldenZoneLevel = X_FIBO_LEVEL_382; // Golden Zone Detection + +// +input group "Sar Detection"; +input double sarStep = 0.02; // Step +input double sarMax = 0.2; // Maximum + +// +// Presentation ... +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +input int sarArrowCode = 159; // Parabolic Sar Arrow Code +input int peaksArrowCode = 159; // Peaks Arrow Code +input int valesArrowCode = 159; // Vales Arrow Code + +// +input bool showSar = true; // Show Parabolic Sar +input bool showPeaks = true; // Show Peaks +input bool showVales = true; // Show Vales +input bool showGoldenZones = true; // Show Golden Zones + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 5 + +// +// Plot Buffers ... + +// +// PEAKS ... + +// +#define peaksBufferIndex 0 +double peaksBuffer[]; + +// +#property indicator_label1 "X121 PEAKS" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrAqua +#property indicator_width1 1 + +// +// VALES ... + +// +#define valesBufferIndex 1 +double valesBuffer[]; + +// +#property indicator_label2 "X121 VALES" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrMagenta +#property indicator_width2 1 + +// +#define sarBufferIndex 2 +double sarBuffer[]; + +// +#property indicator_label3 "X121 SAR" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrYellow +#property indicator_width3 1 + +// +#define peaksGoldenZoneBufferIndex 3 +double peaksGoldenZoneBuffer[]; + +// +#property indicator_label4 "X121 PEAKGZ" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrGold +#property indicator_style4 STYLE_DOT +#property indicator_width4 1 + +// +#define valesGoldenZoneBufferIndex 4 +double valesGoldenZoneBuffer[]; + +// +#property indicator_label5 "X121 VALEGZ" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrGold +#property indicator_style5 STYLE_DOT +#property indicator_width5 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 4; + +// +// CURRENT ... + +// +#define cHHBufferIndex mLastBufferIndex + 1 +double cHHBuffer[]; + +// +#define cLLBufferIndex mLastBufferIndex + 2 +double cLLBuffer[]; + +// +// SHORT ... + +// +#define sHHBufferIndex mLastBufferIndex + 3 +double sHHBuffer[]; + +// +#define sLLBufferIndex mLastBufferIndex + 4 +double sLLBuffer[]; + +// +// MEDIUM ... + +// +#define mHHBufferIndex mLastBufferIndex + 5 +double mHHBuffer[]; + +// +#define mLLBufferIndex mLastBufferIndex + 6 +double mLLBuffer[]; + +// +// LONG ... + +// +#define lHHBufferIndex mLastBufferIndex + 7 +double lHHBuffer[]; + +// +#define lLLBufferIndex mLastBufferIndex + 8 +double lLLBuffer[]; + +// +// HIND ... + +// +#define hHHBufferIndex mLastBufferIndex + 9 +double hHHBuffer[]; + +// +#define hLLBufferIndex mLastBufferIndex + 10 +double hLLBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// SAR Handler ... +int sarHandler = INVALID_HANDLE; + +// +// XMarketCycle sc; +int mSCLength = 0; +ENUM_TIMEFRAMES mSCPeriod = NULL; + +// +// XMarketCycle mc; +int mMCLength = 0; +ENUM_TIMEFRAMES mMCPeriod = NULL; + +// +// XMarketCycle lc; +int mLCLength = 0; +ENUM_TIMEFRAMES mLCPeriod = NULL; + +// +// XMarketCycle hc; +int mHCLength = 0; +ENUM_TIMEFRAMES mHCPeriod = NULL; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMax // + ); + bool isInited = sarHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + if (!InitMarketCycles()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(sarHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + // SAR ... + int sarCalculatedBars = BarsCalculated(sarHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // SAR ... + sarCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // SAR ... + int copiedSars = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // SAR ... + copiedSars > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // PEAKS ... + + // + ENUM_DRAW_TYPE peaksDrawType = showPeaks ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(peaksBuffer, true); + SetIndexBuffer(peaksBufferIndex, peaksBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peaksBufferIndex, PLOT_SHOW_DATA, showPeaks); + PlotIndexSetInteger(peaksBufferIndex, PLOT_DRAW_TYPE, peaksDrawType); + + // + PlotIndexSetDouble(peaksBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(peaksBufferIndex, PLOT_ARROW, peaksArrowCode); + + // + // VALES ... + + // + ENUM_DRAW_TYPE valesDrawType = showVales ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(valesBuffer, true); + SetIndexBuffer(valesBufferIndex, valesBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valesBufferIndex, PLOT_SHOW_DATA, showVales); + PlotIndexSetInteger(valesBufferIndex, PLOT_DRAW_TYPE, valesDrawType); + + // + PlotIndexSetDouble(valesBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(valesBufferIndex, PLOT_ARROW, valesArrowCode); + + // + // SAR ... + + // + ENUM_DRAW_TYPE sarDrawType = showSar ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(sarBufferIndex, PLOT_SHOW_DATA, showSar); + PlotIndexSetInteger(sarBufferIndex, PLOT_DRAW_TYPE, sarDrawType); + + // + PlotIndexSetDouble(sarBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(sarBufferIndex, PLOT_ARROW, sarArrowCode); + + // + // Golden Zones ... + + // + ENUM_DRAW_TYPE goldenZonesDrawType = showGoldenZones ? DRAW_LINE : DRAW_NONE; + + // + // PEAK Golden Zone ... + + // + ArraySetAsSeries(peaksGoldenZoneBuffer, true); + SetIndexBuffer(peaksGoldenZoneBufferIndex, peaksGoldenZoneBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peaksGoldenZoneBufferIndex, PLOT_SHOW_DATA, showGoldenZones); + PlotIndexSetInteger(peaksGoldenZoneBufferIndex, PLOT_DRAW_TYPE, goldenZonesDrawType); + + // + // VALE Golden Zone ... + + // + ArraySetAsSeries(valesGoldenZoneBuffer, true); + SetIndexBuffer(valesGoldenZoneBufferIndex, valesGoldenZoneBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valesGoldenZoneBufferIndex, PLOT_SHOW_DATA, showGoldenZones); + PlotIndexSetInteger(valesGoldenZoneBufferIndex, PLOT_DRAW_TYPE, goldenZonesDrawType); + + // + // Data Buffers ... + + // + // CURRENT ... + + // + ArraySetAsSeries(cHHBuffer, true); + SetIndexBuffer(cHHBufferIndex, cHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(cLLBuffer, true); + SetIndexBuffer(cLLBufferIndex, cLLBuffer, INDICATOR_CALCULATIONS); + + // + // SHORT ... + + // + ArraySetAsSeries(sHHBuffer, true); + SetIndexBuffer(sHHBufferIndex, sHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(sLLBuffer, true); + SetIndexBuffer(sLLBufferIndex, sLLBuffer, INDICATOR_CALCULATIONS); + + // + // MEDIUM ... + + // + ArraySetAsSeries(mHHBuffer, true); + SetIndexBuffer(mHHBufferIndex, mHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(mLLBuffer, true); + SetIndexBuffer(mLLBufferIndex, mLLBuffer, INDICATOR_CALCULATIONS); + + // + // LONG ... + + // + ArraySetAsSeries(lHHBuffer, true); + SetIndexBuffer(lHHBufferIndex, lHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(lLLBuffer, true); + SetIndexBuffer(lLLBufferIndex, lLLBuffer, INDICATOR_CALCULATIONS); + + // + // HIND ... + + // + ArraySetAsSeries(hHHBuffer, true); + SetIndexBuffer(hHHBufferIndex, hHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(hLLBuffer, true); + SetIndexBuffer(hLLBufferIndex, hLLBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Cycles ... + CalculateCycles(bar_index); + + // + // Calculate Peaks and Vales ... + CalculatePeaksAndVales(bar_index); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Initial Market Cycles ... + * + * @return ( bool ) + */ +bool InitMarketCycles() +{ + // + bool result = false; + + // + int cPeriodSeconds = PeriodSeconds(_Period); + + // + // Find Cycle Period ... + if (scMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mSCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_SHORT, + _Period // + ); + } + else + { + mSCPeriod = scPeriod; + } + + // + if (IsValid(mSCPeriod)) + { + mSCLength = PeriodSeconds(mSCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (mcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mMCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_MEDIUM, + _Period // + ); + } + else + { + mMCPeriod = mcPeriod; + } + + // + if (IsValid(mMCPeriod)) + { + mMCLength = PeriodSeconds(mMCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (lcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mLCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_LONG, + _Period // + ); + } + else + { + mLCPeriod = lcPeriod; + } + + // + if (IsValid(mLCPeriod)) + { + mLCLength = PeriodSeconds(mLCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (hcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mHCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_HIND, + _Period // + ); + } + else + { + mHCPeriod = hcPeriod; + } + + // + if (IsValid(mHCPeriod)) + { + mHCLength = PeriodSeconds(mHCPeriod) / cPeriodSeconds; + } + + // + result = mSCLength > 0 && + mMCLength > mSCLength && + mLCLength > mMCLength && + mHCLength > mLCLength; + + // + return result; +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // CURRENT ... + cHHBuffer[barIndex] = EMPTY_VALUE; + cLLBuffer[barIndex] = EMPTY_VALUE; + + // + // SHORT ... + sHHBuffer[barIndex] = EMPTY_VALUE; + sLLBuffer[barIndex] = EMPTY_VALUE; + + // + // MEDIUM ... + mHHBuffer[barIndex] = EMPTY_VALUE; + mLLBuffer[barIndex] = EMPTY_VALUE; + + // + // LONG ... + lHHBuffer[barIndex] = EMPTY_VALUE; + lLLBuffer[barIndex] = EMPTY_VALUE; + + // + // HIND ... + hHHBuffer[barIndex] = EMPTY_VALUE; + hLLBuffer[barIndex] = EMPTY_VALUE; + + // + // PEAKS ... + peaksBuffer[barIndex] = EMPTY_VALUE; + + // + // VALES ... + valesBuffer[barIndex] = EMPTY_VALUE; + + // + // SARS ... + sarBuffer[barIndex] = EMPTY_VALUE; +} + +/** + * Calculate Specified Market Cycle Info ... + * + * @param barIndex: Integer, Bar Index ... + * @param cycle: ENUM_X_MARKET_CYCLES member, Specified Cycle ... + * @param hhBuffer: Highest High Buffer Reference ... + * @param llBuffer: Lowest Low Buffer Reference ... + */ +void CalculateCycle( + int barIndex, + ENUM_X_MARKET_CYCLES cycle, + double &hhBuffer[], + double &llBuffer[] // +) +{ + // + XOHCL bar; + bool isBarInited = bar.Init( + _Symbol, + _Period, + barIndex + // + ); + if (!isBarInited) + { + return; + } + + // + int mLength = 0; + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + mLength = mSCLength; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + mLength = mMCLength; + break; + + // + case X_MARKET_CYCLE_LONG: + mLength = mLCLength; + break; + + // + case X_MARKET_CYCLE_HIND: + mLength = mHCLength; + break; + } + + // + if (mLength == 0) + { + return; + } + + // + // Find Highest High ... + double hhValue = bar.FindHighest( + mLength, + hhMode + // + ); + hhBuffer[barIndex] = hhValue; + + // + // Find Lowest Low ... + double llValue = bar.FindLowest( + mLength, + llMode + // + ); + llBuffer[barIndex] = llValue; +} + +/** + * Claculate Cycles ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculateCycles(int barIndex) +{ + // + // SHORT ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_SHORT, + sHHBuffer, + sLLBuffer // + ); + + // + // MEDIUM ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_MEDIUM, + mHHBuffer, + mLLBuffer // + ); + + // + // LONG ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_LONG, + lHHBuffer, + lLLBuffer // + ); + + // + // HIND ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_HIND, + hHHBuffer, + hLLBuffer // + ); +} + +/** + * Calculate Peaks and Vales ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculatePeaksAndVales(int barIndex) +{ + // + int lastIndex = barIndex + 1; + int barsCount = iBars(_Symbol, _Period); + + // + // PEAKS ... + double lastPeak = + lastIndex < barsCount + ? peaksBuffer[lastIndex] + : 0; + + // + double isHH = sHHBuffer[barIndex]; + double imHH = mHHBuffer[barIndex]; + double ilHH = lHHBuffer[barIndex]; + double ihHH = hHHBuffer[barIndex]; + + // + double iHHs[4] = { + isHH, + imHH, + ilHH, + ihHH // + }; + double rValue = GetAverage(iHHs); + bool isPeak = rValue == isHH && + isHH == imHH && + imHH == ilHH && + ilHH == ihHH; + double iPeak = + isPeak + ? rValue + : lastPeak; + peaksBuffer[barIndex] = iPeak; + + // + // VALES ... + double lastVale = + lastIndex < barsCount + ? valesBuffer[lastIndex] + : 0; + + // + double isLL = sLLBuffer[barIndex]; + double imLL = mLLBuffer[barIndex]; + double ilLL = lLLBuffer[barIndex]; + double ihLL = hLLBuffer[barIndex]; + + // + double iLLs[4] = { + isLL, + imLL, + ilLL, + ihLL // + }; + double sValue = GetAverage(iLLs); + bool isVale = sValue == isLL && + isLL == imLL && + imLL == ilLL && + ilLL == ihLL; + double iVale = + isVale + ? sValue + : lastVale; + valesBuffer[barIndex] = iVale; + + // + // Peaks Golden Zone ... + double iPeakGoldenZone = GetFibonacciLevel( + iPeak, + iVale, + goldenZoneLevel, + X_DIRECTION_BULLISH // + ); + peaksGoldenZoneBuffer[barIndex] = iPeakGoldenZone; + + // + // Vales Golden Zone ... + double iValeGoldenZone = GetFibonacciLevel( + iPeak, + iVale, + goldenZoneLevel, + X_DIRECTION_BEARISH // + ); + valesGoldenZoneBuffer[barIndex] = iValeGoldenZone; +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xstr.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xstr.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..03b33499dcd7e665dc84ec20aa16b805c4d4e810 GIT binary patch literal 15236 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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xstr.mq5 b/BKPS/14031218/Indicators/x-saherelm.x121.xstr.mq5 new file mode 100644 index 0000000..cccce4f --- /dev/null +++ b/BKPS/14031218/Indicators/x-saherelm.x121.xstr.mq5 @@ -0,0 +1,636 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XSTR +// Description: XSTR ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XSTR Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XSTR" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; +input int strLength = 14; // Length +input double strMultiplier = 3; // Multiplier +input ENUM_APPLIED_PRICE strAppliedTo = PRICE_MEDIAN; // Applied To + +// +input group "Presentation"; + +// +input bool showStr = true; // Show Str +input bool showStrUpper = true; // Show Str Upper +input bool showStrLower = true; // Show Str Lower + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 7 +#property indicator_plots 3 + +// +// STR ... +#define strBufferIndex 0 +double strBuffer[]; + +#define strColorBufferIndex 1 +double strColorBuffer[]; + +// +#define strPlotBufferIndex 0 +#property indicator_label1 "X121 STR" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 CLR_NONE, clrLime, clrRed, clrGray +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +// +// Up ... +#define strUpBufferIndex 2 +double strUpBuffer[]; + +// +#define strUpPlotBufferIndex 1 +#property indicator_label2 "X121 STR U" +#property indicator_type2 DRAW_LINE +#property indicator_color2 C'255,106,0' +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +// Down ... +#define strDownBufferIndex 3 +double strDownBuffer[]; + +// +#define strDownPlotBufferIndex 2 +#property indicator_label3 "X121 STR D" +#property indicator_type3 DRAW_LINE +#property indicator_color3 C'255,106,0' +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 3; + +// +// STR ... + +// +// Atr ... +#define atrBufferIndex mLastBufferIndex + 1 +double atrBuffer[]; + +// +// Price ... +#define strPriceBufferIndex mLastBufferIndex + 2 +double strPriceBuffer[]; + +// +// Trend ... +#define strStateBufferIndex mLastBufferIndex + 3 +double strStateBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +bool isStrTrendChanged; +bool isStrStartBearishTrend; +bool isStrStartBullishTrend; + +// +int changeOfTrend; +int startBearishTrend; +int startBullishTrend; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + strLength // + ); + bool isInited = atrHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(atrHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + + // + // Validate Calculated Bars ... + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // ATR ... + atrCalculatedBars >= 0 + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + // + // checking for the limit start of calculation of an indicator ... + limit = + (prev_calculated > rates_total || prev_calculated <= 0) + ? maxLength + : prev_calculated - 1; + + // + // Buffers Copy ... + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, rates_total, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // ATR ... + copiedAtrs >= 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // STR ... + strLength > 0 && + strMultiplier > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(1, strLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // STR ... + SetIndexBuffer(strBufferIndex, strBuffer, INDICATOR_DATA); + SetIndexBuffer(strColorBufferIndex, strColorBuffer, INDICATOR_COLOR_INDEX); + + // + ENUM_DRAW_TYPE strUpDrawType = showStrUpper ? DRAW_LINE : DRAW_NONE; + SetIndexBuffer(strUpBufferIndex, strUpBuffer, INDICATOR_DATA); + PlotIndexSetDouble(strUpPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(strUpPlotBufferIndex, PLOT_SHOW_DATA, showStrUpper); + PlotIndexSetInteger(strUpPlotBufferIndex, PLOT_DRAW_TYPE, strUpDrawType); + + // + ENUM_DRAW_TYPE strDownDrawType = showStrLower ? DRAW_LINE : DRAW_NONE; + SetIndexBuffer(strDownBufferIndex, strDownBuffer, INDICATOR_DATA); + PlotIndexSetDouble(strDownPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(strDownPlotBufferIndex, PLOT_SHOW_DATA, showStrLower); + PlotIndexSetInteger(strDownPlotBufferIndex, PLOT_DRAW_TYPE, strDownDrawType); + + // + // Data Buffers ... + + // + // STR ... + + // + SetIndexBuffer(strPriceBufferIndex, strPriceBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(strStateBufferIndex, strStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateStr( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // STR ... + strBuffer[barIndex] = 0; + strUpBuffer[barIndex] = 0; + strDownBuffer[barIndex] = 0; + strPriceBuffer[barIndex] = 0; + strColorBuffer[barIndex] = hideColorIDX; + strStateBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate STR ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateStr( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Calculated Price ... + double price = GetAppliedPrice( + strAppliedTo, + open, + high, + low, + close, + bar_index // + ); + strPriceBuffer[bar_index] = price; + + // + double atr = atrBuffer[bar_index]; + + // + // Up ... + strUpBuffer[bar_index] = price + (strMultiplier * atr); + + // + // Down ... + strDownBuffer[bar_index] = price - (strMultiplier * atr); + + // + if (close[bar_index] > strUpBuffer[bar_index - 1]) + { + // + strStateBuffer[bar_index] = 1; + if (strStateBuffer[bar_index - 1] == -1) + { + changeOfTrend = 1; + } + } + else if (close[bar_index] < strDownBuffer[bar_index - 1]) + { + // + strStateBuffer[bar_index] = -1; + if (strStateBuffer[bar_index - 1] == 1) + { + changeOfTrend = 1; + } + } + else if (strStateBuffer[bar_index - 1] == 1) + { + // + strStateBuffer[bar_index] = 1; + changeOfTrend = 0; + } + else if (strStateBuffer[bar_index - 1] == -1) + { + // + strStateBuffer[bar_index] = -1; + changeOfTrend = 0; + } + + // + // Down Trend Starting ... + if (strStateBuffer[bar_index] < 0 && strStateBuffer[bar_index - 1] > 0) + { + startBearishTrend = 1; + } + else + { + startBearishTrend = 0; + } + + // + // Up Trend Starting ... + if (strStateBuffer[bar_index] > 0 && strStateBuffer[bar_index - 1] < 0) + { + startBullishTrend = 1; + } + else + { + startBullishTrend = 0; + } + + // + if (strStateBuffer[bar_index] > 0 && strDownBuffer[bar_index] < strDownBuffer[bar_index - 1]) + { + strDownBuffer[bar_index] = strDownBuffer[bar_index - 1]; + } + + // + if (strStateBuffer[bar_index] < 0 && strUpBuffer[bar_index] > strUpBuffer[bar_index - 1]) + { + strUpBuffer[bar_index] = strUpBuffer[bar_index - 1]; + } + + // + if (startBearishTrend == 1) + { + strUpBuffer[bar_index] = strPriceBuffer[bar_index] + (strMultiplier * atr); + } + + // + if (startBullishTrend == 1) + { + strDownBuffer[bar_index] = strPriceBuffer[bar_index] - (strMultiplier * atr); + } + + // + // Draw the indicator ... + + // + double colorIDX = hideColorIDX; + strColorBuffer[bar_index] = colorIDX; + + // + if (strStateBuffer[bar_index] == 1) + { + // + strBuffer[bar_index] = strDownBuffer[bar_index]; + if (changeOfTrend == 1) + { + strBuffer[bar_index - 1] = strBuffer[bar_index - 2]; + changeOfTrend = 0; + } + + // + colorIDX = bullishColorIDX; + } + else if (strStateBuffer[bar_index] == -1) + { + // + strBuffer[bar_index] = strUpBuffer[bar_index]; + if (changeOfTrend == 1) + { + // + strBuffer[bar_index - 1] = strBuffer[bar_index - 2]; + changeOfTrend = 0; + } + + // + colorIDX = bearishColorIDX; + } + + // + if (showStr) + { + strColorBuffer[bar_index] = colorIDX; + } +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xtrend.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xtrend.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..9d4f42499f49bc42b39a659c2bb53447c37511f5 GIT binary patch literal 19292 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 maxLength && + // + // ADX ... + adxCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // MA ... + int copiedMas = CopyBuffer(maHandler, 0, 0, limit, maBuffer); + + // + // ADX ... + int copiedAdxs = CopyBuffer(adxHandler, MAIN_LINE, 0, limit, adxBuffer); + int copiedAdxPs = CopyBuffer(adxHandler, PLUSDI_LINE, 0, limit, adxPBuffer); + int copiedAdxMs = CopyBuffer(adxHandler, MINUSDI_LINE, 0, limit, adxMBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // MA ... + copiedMas > 0 && + // + // ADX ... + copiedAdxs > 0 && + copiedAdxPs > 0 && + copiedAdxMs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // MA ... + maLength > 0 && + // + // ADX ... + adxLength > 0 && + adxThreshold > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(maLength, adxLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // UP Trend ... + + // + ENUM_DRAW_TYPE upTrendDrawType = showUpTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(upTrendBuffer, true); + SetIndexBuffer(upTrendBufferIndex, upTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(upTrendBufferIndex, PLOT_SHOW_DATA, showUpTrend); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_DRAW_TYPE, upTrendDrawType); + + // + PlotIndexSetDouble(upTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_ARROW, upTrendArrowCode); + + // + // DOWN Trend ... + + // + ENUM_DRAW_TYPE downTrendDrawType = showDownTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(downTrendBuffer, true); + SetIndexBuffer(downTrendBufferIndex, downTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(downTrendBufferIndex, PLOT_SHOW_DATA, showDownTrend); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_DRAW_TYPE, downTrendDrawType); + + // + PlotIndexSetDouble(downTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_ARROW, downTrendArrowCode); + + // + // Data Buffers ... + + // + ArraySetAsSeries(maBuffer, true); + SetIndexBuffer(maBufferIndex, maBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxBuffer, true); + SetIndexBuffer(adxBufferIndex, adxBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxPBuffer, true); + SetIndexBuffer(adxPBufferIndex, adxPBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxMBuffer, true); + SetIndexBuffer(adxMBufferIndex, adxMBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(upTBuffer, true); + SetIndexBuffer(upTBufferIndex, upTBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(downTBuffer, true); + SetIndexBuffer(downTBufferIndex, downTBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateTrend( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + upTrendBuffer[barIndex] = 0; + downTrendBuffer[barIndex] = 0; + + // + maBuffer[barIndex] = 0; + adxBuffer[barIndex] = 0; + adxPBuffer[barIndex] = 0; + adxMBuffer[barIndex] = 0; +} + +/** + * Calculate Trends ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateTrend( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double iPrice = GetAppliedPrice( + trendPriceType, + open, + high, + low, + close, + bar_index // + ); + + // + double iMa = maBuffer[bar_index]; + double iAdx = adxBuffer[bar_index]; + double points = GetPoints(_Symbol); + double points10 = 10 * points; + + // + bool isUpTrend = + iPrice > iMa && + iAdx > adxThreshold; + bool isDownTrend = + iPrice < iMa && + iAdx > adxThreshold; + + // + if (isUpTrend) + { + // + // double iLastValue = + // prevCalculated <= 0 + // ? 0 + // : upTrendBuffer[bar_index + 1]; + // if (iLastValue > 0 && + // iValue > iLastValue) + // { + // iValue = iLastValue; + // } + + // + double selectedValue = low[bar_index] - points10; + + // + double iValue = + !IsBullish(lastTrendDir) ? selectedValue + : !showOnlyTrendStart + ? lastValue + : 0; + + // + upTrendBuffer[bar_index] = iValue; + upTBuffer[bar_index] = selectedValue; + + // + downTrendBuffer[bar_index] = 0; + + // + lastValue = iValue; + lastTrendDir = X_DIRECTION_BULLISH; + } + else if (isDownTrend) + { + // + // double iLastValue = + // prevCalculated <= 0 + // ? 0 + // : downTrendBuffer[bar_index + 1]; + // if (iLastValue > 0 && + // iValue < iLastValue) + // { + // iValue = iLastValue; + // } + + // + double selectedValue = high[bar_index] + points10; + + // + double iValue = + !IsBearish(lastTrendDir) ? selectedValue + : !showOnlyTrendStart + ? lastValue + : 0; + + // + upTrendBuffer[bar_index] = 0; + downTrendBuffer[bar_index] = iValue; + downTBuffer[bar_index] = selectedValue; + + // + lastValue = iValue; + lastTrendDir = X_DIRECTION_BEARISH; + } + else + { + // + double iValue = + IsBullish(lastTrendDir) + ? showOnlyTrendStart + ? 0 + : lastValue + : IsBearish(lastTrendDir) + ? showOnlyTrendStart + ? 0 + : lastValue + : 0; + + // + upTrendBuffer[bar_index] = 0; + downTrendBuffer[bar_index] = 0; + + // + upTBuffer[bar_index] = 0; + downTBuffer[bar_index] = 0; + + // + lastValue = 0; + lastTrendDir = X_DIRECTION_NONE; + } +} \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xvwap.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xvwap.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..92c81d06a7108b5b748fb6cb5129281500ba7934 GIT binary patch literal 16010 zcmdVAV~{2=w=Vj&ZQHhO+qS!>ZBN^_ZQHiZY1^JQ&wTsbee0h4WB)%%MeA9W0S*99fD^z9U;(fMxcr+gGl215Vgb+XN7#%qmV~v9M=HKIQ2S%bM^TnJk4}^zofcxOG_qO4SqJ zohU{!*Sj8x%&ua^_kGb){Yl1MN5wXkzy`nbSY`+<02(`plqZXF-;ju4+lhGwJmV7) zpbQ?j)?c`h9mlX(LOGWa`694(reHg0{z6DmZFys4wgs<6vXU#|X?vrQnO|sYgX|ZoJHaXa}Z0 z!@R>ss)dS(V_66+uSyC~<^0BGrUTu;Lg#yR-$1~RaB8!X;B;ts6bNcMWHZm&K@e~u zaGRyO7W2Z0So@^*PRbZL4#k`klQ25L9@R5H{dgwmg8Rd1X3jT2R!!BK5FjDi?Qfwc zn?n?^-xDP0-$L{)V>{)jZIRpeYAcF}QNEg%?aZTi>qk0H(QAY@b0TX& zzK8pw)Qwt|d5JgQI9!Qx0OZIaY&^U-XzTIl9xN}*>jvWHC@RbsMhaHdz25DwJ;HpL z*{wBNwKdSdSCwMo9Pm3T2SAVaHzgb))`?x1maI`}z+Mmv+Z?W}zU6Oq-o**daaR+o z{*EM0XNNK^mx`=r{&YABvL2V~B4hKnBSYZQI$pqE*a!X}U~FK_6R45m%;W=ID2^#l z&#v{B-nXDPC-^hsNhik(RON;n>{w*?6$OIYM`>MPFUJwzJ(Rkh5(9-`giB^N92bFD zngaKoiG&n%@*}nA>WV+m(5^1>>SGb>A6Sdhy(vEpsH%CSyq~vsY8k5_1x9G23)}Xv z!v0M5#uBlGl*H9z=%78&-U(U#^Azc-ToRRU&PobrVjj6Fs}$-|=ppP{kfiOiAYp0JWY>p(I zDx_q5p=fYnv2D-|%Qn17mV*sqyP*?X8NN8?Xk3UEXv$I21Ai$2<%J7hnQvGFFe)hr z9+BvgxU=)=U%mXSe&1rFb5};Af$L5~+Vw&!M^HTw4$o1^1R(Kb$x+lyYtW5FC;f_+ zijiVv$85At@pn{X8D18$+V(HN!D^1hy3X+`6kVoXjL3xj!TnX70a`@Lrw4Heze<;q z$FQ9vP7ri0{`Q#oy-E}0F`t8c1f%&t8AUK}-!XTHQE87@!HuWB|0Ig7b<5%J_DdfmZGDMKqe`ph2i}k3`C}yc4(+Sz5b`Rs zutGp$h>BE&C0Q8EW~ zfUQHCB061lMv(CyW215tv|g#LL$eF&F*Z`{Vum6$W%^(inhb~JLQ4c0*AlY(&gZpD za#1lhe88Iwu1rs7D(yLMC-Wd`kvXA6@ZLP`0jtr8?s2vmBG_fnSY?ARI_fuMpS?5J z&wlPTgVDplY%Amp1dw@4o+}dp(d@qr`AZcZGF*^PD%r(uw@DTKVOzK4c~e(*FAKdH zkcY2F_9Q~r#-kI5aoWHIy^2E8^yOaJb8;NfJmg!lsm9HObihj0{kbV<|HZ^;S=0G!r^pgWBc(|ldX~?P8w)}e2r6CpY-(>De{aqH zHJ|IDNK3u8FA_cv&QG-aiGu}JS0i(*UTvU{F*g@!C!rj`9Ej>JJ@i|t@SxJ%nC7m$ zYJ|wqiTA7KQq@yvMZ5CZ|eKFz1MYAMRwU$PkGpDNnN;~B&0OW$~7rauxg4*ul z4e=qc0A2sG&+3)6ce9(@Dk=L>I>jPmoAJw)XD#m5sa_(rrVHsQqk6jYvAF#HyMQl$ z(nq5re~?X3(IqdE>f(+}dM{pvEtAuIbvU-?sc{1d82IS-z!N@O${HxHF8A**RG6YNKYSfZSun}U-uYm@l&D@3)C;K*lxTWGuLN|P@-V}G_2vYNac z#ZBhwFPQd1Z55w)$W)=-c&J(Wr&2^^&r{P?R~n{DT})^%NWoiL0uYQiYAn6co|+u- z%m$)pLHfvHAuJD$Sa2SauD`*w(UsGUU}?0Ytb)Jh_Yy`Fk)4llTp(VmTpYX1Bdr_ zMu=$G<5?eYL?p7Rgt3@SnJ}(zG34pjovo4z6;dOyelQcUNmjSp`-?DEAstfz6SB%= zp=|te;9%v0(f#{2N<1e~cm06w!CohsAycQJWn!)aHwG;GD( zRY&6DXQ2=m(SCCC#^tu5oZ2PQyVSec=0J?x$zM&5wqoQt)d^~F-HD^X6{dS%52pEK zQy$EwA)Ar3w0{_Jm0RzRjbx9X>(fYFj*dbd#Psdn)l@=e>t1;G;qvq`n)H{J9rAvs zR0Fe5j5r9C)Wk{${aTULRWV@rJ4zF;nh}-L=<|UzzEeNN`ZYDY0b|pt4}B?S|R7Ee_(yCBf51KVBes!vW(es$nj1RzegLc_`VARpAJRFn!siPyk#*gX=7ea% zNFF5<+%8)V`PY2thk@)AVN>6%~l)W+CyG^j^e+_&-997Yya0#m$LTb#FY zXuO3v231zLQS}ljB|dp`1AoWmyt`N6QRD}Mz}PFfTk)nqXnC+%9NmQ+Whi-ohXN%CGct4sXc3-+Xbt} zQG*u3HEbd4^aC{`HxP82m3_u7>US*IXh{AZbM7!`0b)P#(?ccmlXI$P?`LnbzwThDl*)RH9`MVB-4mzkm{59G0^}aMVyBPiEBGr%5_T;Hd?h zvnPmdUBA@mlk5MP_T=p*X6JM2!B+6R`dr{KH%Gu#gxm9cmHd`Ql9?MDqHsYRkkz#0+Uwn&7Sm?HO!q`=Nld5rX{*jdIbHI8Q3-! zip;LV#f@VEU^1_|b%KM?y;;~m0dgkfBF_Y1KT%ZVE(Wl*$yHOmONa16DAg@S8+a;!E`BZ|T z!-{~0P3go6vJ-J!PLRZMUw8>yR0VAj#NTrfZY`UFP*J_U`307aDvO-VagebViOwCq zeup-jcpMDhw{P6fL`$n_ZhC+^$zl*OVv|~C?D6|#4+|=LEy;b{kJ?A3&*f#^)X-c6 zXm6LuS;)+1LbHLBG>i75{aGYs8>oCkOtmc|J2G&Fn>cy?4pwA4kOLG(Y0#Ov^G(4D zWjCd4RBuPb8A<*|EUDJ@pFP9dZm_A}M0#m5*$ZnVq8_bVdT%CZ`x}sGUJ-v~bG zK`?vyMzs)G22kogi4&P&lqaL-qhN9^y_SinSdin0==5?Sm{yv2k}0-CC`;uR$q6Ub z-aiD5$@AlBC`7{=-@O|uf|V)d&&l5E@iwWHv7R&uyatiAK9P%;ID?nIGu4K-T=+3g(G|S2KiCz`K&rI9JO=F zGRL=s4uWnyz|d+aisak4J+Qa-^Xi?nFTnDvx#>&D?LudjM1!ewNP#mfmvtFm1X~(A z1xRisi#Ygq*!iKb2dg#vWMuI&xkmIHfYGe-#t{}==Xzd*qtB})q%idC(I*Z4DtO`N z=eEjkNleGbnQ*o{0|js;DH+YajN{q1_Tz2Vc2<6ZEoE?qY*MuN=}*WO2cDbU#(z_~ zaHO9Lxi{OUW6#IO%vP-lhpA_uvGj>pX&#i6RUlvcdGNe6{K;oMSXIaIRbsh6l26u< zJ2T8$ce7zYS)xvf2mH8uZy7;DgSzdrN9`PCwhKSG;e}ImCF}wjTVfPW!LaBSI1JX= z<`Mm(*jO`dK+H;)Y^3%VJIHr9OmfCEZw%_zNTD!FlO*PFDCZlQ4p(OM+Ro<3#C)|l zYASUlQ>~p-=@H6w(&yG7H)ni6Vkr=z@4-=TK>O+({L}k8+-!)gc*9yy>^GHckC3g_ zFkR~%W*D#910Ug=PY0bX^8k5IeT35N_oJUe90YD?)V?otF0y4>fzvR57kh`O*l!fr zgd3gr2dREDtl)wdHCKMd*Ljq6L3s#qEuMkHzrw+d$eoaubpulBKCh)CC{Dd33Vo@b zxcg0g(L3hZrBeyn($ajqZ`XU-&Q>NBf@itu<(pPf-}qncz~X+{++)svh-bmBlzWo0 zJf{S8#NTNH@9`v+;uZM*^e?GNc#zCG{mt;@R!NiXjw*W?G3J`?SxZ(sm+qy%@lRaa zFc=vr1Jb=FAl%PM_&V8zbtHL~sh~iT#rF3^z{pd`R1u~@Ak`~5akE*8l6$X;vSmDq zYxua%uYg~aAayixWF?}waFhC-fCvGk`YiFzuj5Jp?UHtU2qGzuvcI}Gq}Y%CjYYbh zsPkunL#w+E&)};=Ua*u0mUnDMJ(yBs&Hbuw-f4Sx_&mUVlb#s_nigy4wdK&(w($Nx)Lb2`6B$RmbF2fMPP`=NnCp?=A^ z6~!J+2H}RI{0E*hPRn4ruIfuq+x#6qLA>}I_!m&$5h8mi^&0>o-3m*h9tmIIf?XrZ zOpnGjbd*M$zJQ{5>dTjK>-h_llsj_ zC5jovPW6obAykT9L^p0wf(?JLOM@*K&1w%11mBJ=sdfZ#m*0Ix#1H|NRJ?6pY%c%{ z`kffH*tMN+bufdyVT6tPA@N6-D3gE>YmvKE1fKcXm2t{!b^!VW!G=Slk@;@qRw|9T z^w#%5o5JKvST^EN>kq7>unILz?s8LAvbx_fdc-i z#B(_yT==5aZ${oNo4EzAxbo`EqLD=R>)m6_w?eS<#SFOT@h`8OL?}ie5>8x*UqCj@ z!Rww-i~^3(1(;b*+0c)nkEWgVlvDkmI>o*_>=?c!nA;+?zP(m6IuynXxEQ9-zDeGD zJ&m&{^v3K4SNlNGQVHeWOCX}5cGCk4U`qTONBtDcah{$f`aA!MBEbeyNTw1Ej_il6 zXe=lmgM2HEiLA|pejd>sdvpA{=5!R8EP;m>i@z!#FT^-G+ndpMkd@H|klm)%UdFBX z6-CvQh(QwlfZ=srMrD*l!3Q2-v1D>!UIQp3i)o>i-1S85q>NPybmxti#+ z?RageUxtvstAM$D{LDYA-4Js-4s( zVXyBLWg`a-^9n;R(_UwV7gRaFJ!H0rVH7eI=D%CA8Uo{jM=kc@$TGo8kSWir_ymBw zKwUIt-757L`p*PRLW0v;ai6s&fC&lrYaw`jw3GxMkX%H=C5l~tPV&aomhRee3VIl? z_2!k4Q0QrJ^iaJ9Dds9{Iobm0SkBEYvy!|@ysjdqzVebG)#mP}dS6=-48%frH_NY4 z-{c|Y#RxJU8asE(+2XNfr6G)_aC|&W72~6L`pZxgnAv+3{!uiJBckQvxt`gC8w^KF-SzUy;Y9i#DW@4EuVY6z*8`fVd%3JXC!q zSANyYO!8|3ZCh%YLv&%3;B*zP2GPpQU?crg03K_5--Z9dK2QKr2)owET%3LR6S7E* zYPpqdLiL6y!uQqDzvIR1;G2%6`sva^Dw+03)GM7HzS0Rl+PK_9fwM_kdff7mg9vd( z!3Z>G3au{-C0#6k^%>Dns!j#buk2>W`DfG5jC6RNi09)@>x(=9WxA5J31#T*Iz6(; z3c|qr$fYh`__<2Yz#vH5VEu%yIBjer!m6j2n~%gb zJO$sS@PbjPH&DBx!R-~xf^?siD0d5e1iGe%j-(QnGC1GRy>)%$Z$nG5jKYuaNA9e_ zaj`hA9uf+dnLd>t7qaragHMUu-HOXB3eHVAq2|lU&6(fubEO@^ z_LuZbUtuto_ij=gHEe-cn69r%eG4Lw@FNX>j(MWu1JiygR+>wbw z52aBd+srK-?p*u@865qYhi4~5h43;rV*7Bvkra11`jbn3#H1B+hoRKBqMFIPerarq zO3s&EV`1)f3oe+px@?8ZE%B}aEQKN?H*Q5ANnJ$2HnzE3&Bd0S@H4L9u9FIQc`Ca5 z>OIG-Sam#ONFw>vn6rwStMA$JE@+(Oa-1j56Dq6wH!<`~RS$i309dlCy~&@A0lpx% zeQI|d0?sXP1*?3hFkrXim(*Kl_cnT7vapx2Rpla_1G+jpW1H_s|LDF)E^nJ4Ow#Q; z(LR7L2Jhv*^yzJ)vT!3U8%9Pf;#{`3Q4~#p&R+GH+0u`V!AQn7J1DhH+GBDItGA?B zyWLi#j8zJfz3!5`3-Ud%J|8?k_KrzwujycjI`3rfG5IPL>aK4G4!5WjhC|4jeNl8D z)b6T~U;461vI2QNv>=X4>K_YnF2}qWchv0zQQkR5PtRhhzT2L8Tm5QhFyn%V_Xb*m zNMU$742ymq+k)_@b*&g3Y-o$-lr?XDAMW?+^I#M$>^VzjM1Q8$p|*sJIvOEsni^Ik zZdy(Ss!;_~{4(I?a2s+r(Wm7G3OkbWwGQ=g(Ok|#5>>-EF|pC){ldAs;snFbc8hO2 zk&=*9G?WSJh`7OSM1VwEX=%9G;*`!!p!w`!7+TL`y1TlaGd@ZxJmDYl%&1qhd~j$A zB2?LhmgYWD!WH=^#oxF^;aoAG@U)3@9tH$r)Q^rp&5dejm?+jUa2EAoi8@NV&0Uo{{{ zmUvDrFv8kG@s?(!@*j%1?~%VU_^F}rO?vLfiyi7F5(qB~!m-EKpwzgQnO;jP(M0@J z4iX#6mGmPfV=oFja zzv}F$x#gw_;xFPw(lv2W4NDTdL`@UU@$-YY|9z^@XzQZufQ}qWH$OWiZL|S)!64ITiMgOTo zDbc(dsc>&>lc!BClNu6Lq7Z!ZpxQ)kLos)}hI}SAS2p})bJH-Izm~YvxOkI%1((I! z0?TKA#t#s)@;>(4WeCSQ(xBM_Y_$DjlNw^Mfq|NV7Ycm1#>g34Sefi)p@9?390BFN zYy7JcxQbn0{oHQ~^N3Hn)D~|Y%?!7hf?G7AAKtA5kbg*(moh2PXZ^^@UMONjYnnn#~Wscr_IPd-`Yz!_=|(9 zR6k?a=!rS}O!G(}Y?4)zs0{@Rwnys`C6RPT zAFoZ{-8IqQDcFr~J{u5`PTy_%FaR&j!6N#$m}6vuN%n;{;_$p_Pb*KC-yA`v34=d6 z9t2DVm@vy+l^aGNPDN^+KoY6}+eVmhPyk=QE55&CYw@GvM);k~dY24nCUxvVhYsPy z%Dg{nJB%W+Q!Cukvv5XP{Qdzv@{6ZY-Vp*3>tWX%oKZtFbDfTZNT zou%k@woZgc_?nK}{iV2~ej>t`O~~uo+nuiqoW0e_IMxtTpldyP_)*3`<@hZZRUw6)g)}#Fb3oXD zX5*4|e5b6wPzW*pT^4sA;Z*Hb$87u+nPlc}Uq zb0@ILfaNk9xb}w|8;WsUZ3HW3-B)7C7x0+jk_w8MIPoSjb=gT$+A5Up{7FcVNB(mnzuLkg`mFj;3E>cuK6!L>ukO>bqeGCh|7|Q z&M$c&P2W;CmbA_vEm{~QU=u+HI;#fs40@D?MIE$RS=4(oKW3L1s>)YKbw7S8IR&gp{m<4BiO{Ptq=I5U1oo3si5=t33wK zikRk>lvzzeubuhYZx{};>6TjU=4uc(VYq)VWQs0_o%%`pva$wn0( z3Qmo0v}mt4R2&CFxTqzIz{xZ~Hw;u3p1u;)ydH*!7J2iD>IYe#bC7rxkNpZLA$}4@Ylw9i{T4W9~s3!6HlSSkd!+4LhkA3f-p=#el zN=8q?qTpdnT!RIUpYDayCD_Rqg1MngEoY3os9y(CWZyy`SF6djF_>gR75Vmwp6g@f{l zLv=P_%NlJkBr)zeKm* z?moKW)p}k(YXfp=I^6y}rzIDSLGPT-%ZYNUyn?<)>reivN`91C8{ckPOU->J;_J4b zF)<~ld2C^_H@^RhY`~t8K9{c9B~DX;nV&B#OXdOZ<;=_=gYB)%5zl}W z)9>R^1R!RIEMGcG1_JuH<Nht?Epw0pLF0ah zJ`rY^gK+K(vZ(k}cPlvLbjH5Nk=@f}9**556ItP^+6h`-JQdBM6?VEt>}Tl)rEO^` z%`^U`hRR%s5Z79Qs7&VlMg*B)_W!ySL6{BQ5_0H<5#!=4WHq%Zz>?t52*|&aBlV|>RcxYJM^JLq zwGuaYI^IR+9*8ApUE`vZ?_(+)o4Q^`<0H54F>w|^r5WN2z{7h#+^Q+OR7FfA4|hv4 z`KRGM(pOubyeBK#`i7hpl88%NUJ2eO7HYoD%*WU;f%%j48q5;_Ru~Y@;VZ{pAco|dOR((O1y&G8s|1%RAhx@j zIgl46lsq@gf)6s$M0S*2QbVleSD~_0TceEtxYln5j&=&hGgwzymW6pNZ zsD~>s#((qBBiX+_uA*3e5GnZ+_bL80$Q-;Ul0FAhUizRuWODdOpkhV;Z68@yhJYjh z&XoT1D-7K$EH$@Ssp04NZFTHNFlZK8c>0`IIaF>jU&(kwog}b}>(V`ie`7iZMa5A_ zA;-6IR^2Dr!S{B|XbazG!ugNLzV-u&^Y6R&ZuP6agT%YP>NZ#M-V!q*=dM}bbl%r$ z&S7H_=v%+t#8}3eUK~w_>G!dt_=$dwUEO(jZFAIbkxo)dRg+wjoEEC4wYp4v75a*} z60M^Q0~id1@1Jx=f|Itb@BPCm@msOf-*{8K_%Va-3N*ctGm)<8TVpBudI@y!c8+r8%!OK7%+UFq#Lgb;!+j^=NF zK4XVWd56Q-j^_MyBT}tjFNk zjelz^4(Uu+JuJnDX0m~C=?Nw{Uhf7#dh^2rhmHy0(Emw}|0!VV}Nf2*f0o^ z*>BUkJlyuzbg2OFmHTppoaR>61`Q0*W9-*v5pZ{Xgh&~DmNrE~6p9btql@-x#tId4 zhBQT)$MRnRLIWQ)!pJW>UXxd8_m)&sN9eFSY57*uS}QItLejmAyVnAU;AjNZa98tr zU6mKSQs(=1J8%3g4nqaNs>#Rvr+vx9T&qE%DQq%ks_Sn{-I z?%Y+0BERv(zmLlZq#AU#x38;1h0kBt5a(uF1-V>{6+) zpUT8S$l{5=RP22Y?=?LL7r0-KM?e0gke+G^+|f+_P75f^t(oyCeOcLY?Tr+z(o9`vd6Vv?db)$6+<*+qA<1l(7j$*xd*!X zn{kW6DHuMrLR|;@X$}E~juHz`z48?wpbKAp75x%n+PQitt=YF5##vzSNRt<6`?(}4 z`Xq6};NcA4Rr@JOUx2vREg0~&a+V}7^^h97ZQgL6#kd}Vpl=<=ovd5quCq9qt=8zh zYjY71p?*WJNpU8D8Jm--aL$9rrUX{`glxI;9{3)(Y*FxerG9#Q-{t*=)<6G9sV%gP z*OT5}B~8O!P^Yfg$hMT^Zun@&UG z^daiQFl>pId;N|-L2|(Zc5bLieJBWJ`|g2(apVi~APJ>KO~}ACO3|ENKfN_J>oR$R zf@4zZz$0LS>|<*U3w36BonFEzNBN!}P5T;Y*0t74*7WP*^^4|mz2jy&9AiU<`7l@S z%E%0OapbKwPD%&`A`108>25VCmcx1zd0su5f60XI%#cw0UPc)3kfWtSwqwtkLtQB) zg)UG90UEwhRZ!n4QO<_NB&R2-@FZiOoP9*W6bfTWpZ@Q6GuN;v(R46|hl&*h{jBay z4Ty~9{EnCz+9<T+D(OnZMO!rG_ALQIGZaO42{e@&x%`LnX$6$tw<5*^DPhhza zj%gR7s&@#QRmK-dX)k*?;A`E3+|9zn2q<`m6gy{U)D7qv)B(k8dlS-(!Lz^O#K zue)VTqGar|EyDt=C&(r{E9BPNuh0dkF2y@bjfci%zdxll3%uWzJ}tGv0Vh>wfS3W{5Vte2Nh;)Y`BO=DJe=`#(VjwXjT}IsKm7JJ637om^%Xp1G83&p0@Azzz9gHFnY@M>Uk8I`P^GrmCr1W#;C zD)Is%zB9z4WP75%Xxg6y5G`N?Li)jj%WPK`a|yhUVHM-0PU{}skl8;jq8wOy78^OX zM#tp2UNM}1Z_;>J0%6o+1y_8jn?Vp+cewycI6rQ7f^X^sL5Q(*bni)6^XukPQUc_R zi!5zfNp?}hf2GGnStqCIgL<6+F8MiQ)eld@z-L|XA z0mf;rO#MNRo6%$DaqD^9&|e4S425QFR5dr|!fJr7Rs)a^=_P!1$Q(HY-ra&Rr|BNm zJ-LYerYopNyLo@d>NH=SF1p# ztTjjekN%9H^l4iqKN|VsdSx!L{%Yfh6CLHkag*aaotX#Rpncu9uD^6Kj*XdAbureW zCQ%4-3@z%(R`uD=Q3JvAxjn}IkeqS$# zZ2OelG%FAw^RIJ}m7qhzBNTApMoI`@_VF}2Jk#ztiS{YBY{du=TW?nqNPC_(?KJr8eqAJC;G0Eqs_|B;x24K{Sf|Fi77P-b1z za$CSo-%?oq`tSbXU2|WQB70$!o9#v#G%;b!2=A1VNHN##!Xw?LfFk1CRx*^kL1g0_ zp?6Bq>8wO;X&N5j?OqS66J~*rrUomqczcvaCwT=2C9N~8{-weB)pA8#jsx6u6Vv)L zYQ#heDXTUfrK7Nf8g1!KzP}YhMda`%>O((djahjAO*}(!%@28HGL^H+@@aT&4Gq2K z_;SMgC5Mm70yrkvAKU#{OILA-n!I&q*tmuoB1ZQ4(iFql)N&=9mo~K|==sVKTU(=} z;~rnt^^yJ%1c`Ds{8+)zJ-xUY}O1CIz5$yF1}9NP(@{muOri z3r%5D$UG}zSTdu>glHhzvS(71h>9XrG7`A5hib^_n*UYZAK88bTt1}VAae+WO)gW_ z!hD!Pz!Bgk7o7w|gj1?XUrC4^>!FPBXPtg&-$aKv|>Uc(` zurBs)-$GAaG##R|!(v$@YnL`j%pFFg%hG@f^BZcZDn=aAX>eaEB*G|CDM7TH{7xQW zX&a0S4XI%$!CS>_cM6niWWnSufV*n%*>q+TjMTI?T(G^ZNeRYnOq+Pa`W(T(WAxso zZ7>`qfgh73_z=e7#%cDEo0|M5v>H^js(hR}wr$g_6fA-c)l7vpK8dJg<1%g>XL~8N zxYlCC#tvg!rMS_?%u2-Sh4Gx@vO$n+qT#zp4-P7(?`wE}95f(B4q#MqT0=ec3M%pT z>g!lsuBLV(L

    GgK4FI>D_thxdQ43GrBJ14Ohg4M=W=Sov5TZDc5vh>ebHNr^XmODYO)H%9)@PkW+}D@^g548b36J zP{AU2#^#lM@E9W7-#?8S94}K}^1uQk;S_?zyTn#@mQ*X3Pd|N$h1>G+nW+il<1Ws% zuq}KRbF9e$jP!w$Hlz*yy>5;zz)OK8)Ejrhqc947CWelGnmUO-I`qlSUPA?SxTTz| z*SUCXS!Q<@m`l@!3&87sXy7LrdjFZW5&lbQSQgrUpejM54*kSOrPzP2roGJ8#m#9B zi?9xJ#5kUSIfSvdc8r+0Hz+5GehKmu@_ue@1As^8piY^bEDE6P;xLMbT=SnD_sj?p z+p>US(dkKGp{szS;d({~YZa8e6PT_;@Td|(VOk1WX9#%egA^lUCREc&6GcoZf}y@o zbLfe{!u$OgvqTGSi1pGKO#<`%0AkM|vW~Ef^Y){y5G`K;Un^mP5oP=T@qdo`91-NM zH7`bRI7I7uNJUY2bWWC7tt399Mn%6gnK1Gu~AZH6RSqCP1`;#w3SRGYp$ zd7=j@YKs?kQO2XO2;xdzQ69PAQVQNZpft)Ow{o1>A1O5Z_Jn->eKe^7K4*(^bezwvoO5&-SGHo63A}9mN8kB5*RnzA8;j?WusZvhjh$? zX7z4T&(y&PyJT#m9a1W5d^vgsY6ZXT>N}*hdV)P5G{qT@mLa<4K$mg3tQau*;xgPjT@sMqT4WS zO7B*$7fbz*{{iR_f+ne_pGh&ERD?4@Ged`!(`Z6{SiOOUeHpauJs=#oUf5)8K?b&g zgTcj0MrGUtNewebZ7dL)G5F8@Z{eEJ0oN-HxzgH{-~;n%YliNKXjDltIMTjN rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // XVWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Fast ... + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapFastColorBuffer, true); + SetIndexBuffer(vwapFastBufferIndex, vwapFastBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapFastColorBufferIndex, vwapFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Mid ... + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapMidColorBuffer, true); + SetIndexBuffer(vwapMidBufferIndex, vwapMidBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapMidColorBufferIndex, vwapMidColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Slow ... + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapSlowColorBuffer, true); + SetIndexBuffer(vwapSlowBufferIndex, vwapSlowBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapSlowColorBufferIndex, vwapSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Data Buffers ... + + // + // Volumes ... + ArraySetAsSeries(vwapVolumeBuffer, true); + SetIndexBuffer(vwapVolumeBufferIndex, vwapVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Price ... + ArraySetAsSeries(vwapPriceBuffer, true); + SetIndexBuffer(vwapPriceBufferIndex, vwapPriceBuffer, INDICATOR_CALCULATIONS); + + // + // Fast State ... + ArraySetAsSeries(vwapFastStateBuffer, true); + SetIndexBuffer(vwapFastStateBufferIndex, vwapFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Mid State ... + ArraySetAsSeries(vwapMidStateBuffer, true); + SetIndexBuffer(vwapMidStateBufferIndex, vwapMidStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow State ... + ArraySetAsSeries(vwapSlowStateBuffer, true); + SetIndexBuffer(vwapSlowStateBufferIndex, vwapSlowStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Required VWAP Data Buffers ... + if (ratesTotal - bar_index <= maxLength) + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Prevent Moving Forward ... + } + else + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateVWAPS( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + vwapFastBuffer[barIndex] = EMPTY_VALUE; + vwapMidBuffer[barIndex] = EMPTY_VALUE; + vwapSlowBuffer[barIndex] = EMPTY_VALUE; + vwapVolumeBuffer[barIndex] = EMPTY_VALUE; + vwapPriceBuffer[barIndex] = EMPTY_VALUE; + + // + vwapFastColorBuffer[barIndex] = hideColorIDX; + vwapMidColorBuffer[barIndex] = hideColorIDX; + vwapSlowColorBuffer[barIndex] = hideColorIDX; + vwapFastStateBuffer[barIndex] = hideColorIDX; + vwapMidStateBuffer[barIndex] = hideColorIDX; + vwapSlowStateBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate VWAP Value for Specified Bar ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Specified VWAP Length ... + * @param _show: Boolean, Specified Show Buffer or not ... + * @param _buffer: Double Array Reference, Points to Buffer ... + * @param _colorBuffer: Double Array Reference, Points to Color Buffer ... + * @param _stateBuffer: Double Array Reference, Points to State Buffer ... + */ +void CalculateVWAP( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, // Calculation Length + bool _show, + double &_buffer[], + double &_colorBuffer[], + double &_stateBuffer[] // +) +{ + // + double vSum = 0; + double pSum = 0; + double mSum = 0; + for (int x = 0; x < _length; x++) + { + // + pSum += vwapPriceBuffer[x + bar_index]; + vSum += vwapVolumeBuffer[x + bar_index]; + mSum += vwapPriceBuffer[x + bar_index] * vwapVolumeBuffer[x + bar_index]; + } + + // + double iValue = mSum / vSum; + iValue = NormalizeDouble(iValue, _Digits); + + // + _buffer[bar_index] = iValue; + + // + bool isBullish = low[bar_index] > iValue; + bool isBearish = high[bar_index] < iValue; + + // + double iColor = + isBullish + ? bullishColorIDX + : isBearish + ? bearishColorIDX + : neuturalColorIDX; + + // + _colorBuffer[bar_index] = hideColorIDX; + _stateBuffer[bar_index] = iColor; + if (_show) + { + _colorBuffer[bar_index] = iColor; + } +} + +/** + * Calculate VWAP Required Data Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPDataBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double price = GetAppliedPrice( + vwapAppliedTo, + open, + high, + low, + close, + bar_index // + ); + vwapPriceBuffer[bar_index] = price; + vwapVolumeBuffer[bar_index] = (double)tickVolume[bar_index]; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPS( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapFastLength, + showVWapFast, + vwapFastBuffer, + vwapFastColorBuffer, + vwapFastStateBuffer // + ); + + // + // Mid ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapMidLength, + showVWapMedium, + vwapMidBuffer, + vwapMidColorBuffer, + vwapMidStateBuffer // + ); + + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapSlowLength, + showVWapSlow, + vwapSlowBuffer, + vwapSlowColorBuffer, + vwapSlowStateBuffer // + ); +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Indicators/x-saherelm.x121.xwz.ex5 b/BKPS/14031218/Indicators/x-saherelm.x121.xwz.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..8c7c1327fa22ac27d0d4ea0ec3f83dad366deec3 GIT binary patch literal 113410 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 maxLength && + // + // ATR ... + atrCalculatedBars >= maxLength && + // + // ADX ... + adxCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // MA ... + int copiedMas = CopyBuffer(maHandler, 0, 0, limit, maBuffer); + + // + // ATR ... + int copiedAtr = CopyBuffer(atrHandler, MAIN_LINE, 0, limit, atrBuffer); + + // + // ADX ... + int copiedAdxs = CopyBuffer(adxHandler, MAIN_LINE, 0, limit, adxBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // MA ... + copiedMas > 0 && + // + // ATR ... + copiedAtr > 0 && + // + // ADX ... + copiedAdxs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + // + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // MA ... + maLength > 0 && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // ADX ... + adxLength > 0 && + adxThreshold > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(maLength, atrLength); + result = MathMax(result, adxLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // MA Buffer ... + + // + ENUM_DRAW_TYPE maDrawType = showMA ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(maBuffer, true); + SetIndexBuffer(maBufferIndex, maBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maBufferIndex, PLOT_SHOW_DATA, showMA); + PlotIndexSetInteger(maBufferIndex, PLOT_DRAW_TYPE, maDrawType); + + // + PlotIndexSetDouble(maBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // LONG SL Buffer ... + + // + ENUM_DRAW_TYPE longSLDrawType = showLongSL ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(longSLBuffer, true); + SetIndexBuffer(longSLBufferIndex, longSLBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(longSLBufferIndex, PLOT_SHOW_DATA, showLongSL); + PlotIndexSetInteger(longSLBufferIndex, PLOT_DRAW_TYPE, longSLDrawType); + + // + PlotIndexSetDouble(longSLBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // SHORT SL Buffer ... + + // + ENUM_DRAW_TYPE shortSLDrawType = showShortSL ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(shortSLBuffer, true); + SetIndexBuffer(shortSLBufferIndex, shortSLBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(shortSLBufferIndex, PLOT_SHOW_DATA, showShortSL); + PlotIndexSetInteger(shortSLBufferIndex, PLOT_DRAW_TYPE, shortSLDrawType); + + // + PlotIndexSetDouble(shortSLBufferIndex, PLOT_EMPTY_VALUE, 0); + + // + // UP Trend ... + + // + ENUM_DRAW_TYPE upTrendDrawType = showTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(upTrendBuffer, true); + SetIndexBuffer(upTrendBufferIndex, upTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(upTrendBufferIndex, PLOT_SHOW_DATA, showTrend); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_DRAW_TYPE, upTrendDrawType); + + // + PlotIndexSetDouble(upTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(upTrendBufferIndex, PLOT_ARROW, upTrendArrowCode); + + // + // DOWN Trend ... + + // + ENUM_DRAW_TYPE downTrendDrawType = showTrend ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(downTrendBuffer, true); + SetIndexBuffer(downTrendBufferIndex, downTrendBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(downTrendBufferIndex, PLOT_SHOW_DATA, showTrend); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_DRAW_TYPE, downTrendDrawType); + + // + PlotIndexSetDouble(downTrendBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(downTrendBufferIndex, PLOT_ARROW, downTrendArrowCode); + + // + // Bullish Momentum ... + + // + ENUM_DRAW_TYPE bullishMomentumDrawType = showMomentum ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishMomentumBuffer, true); + SetIndexBuffer(bullishMomentumBufferIndex, bullishMomentumBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_SHOW_DATA, showMomentum); + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_DRAW_TYPE, bullishMomentumDrawType); + + // + PlotIndexSetDouble(bullishMomentumBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishMomentumBufferIndex, PLOT_ARROW, bullishMomentumArrowCode); + + // + // Bearish Momentum ... + + // + ENUM_DRAW_TYPE bearishMomentumDrawType = showMomentum ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishMomentumBuffer, true); + SetIndexBuffer(bearishMomentumBufferIndex, bearishMomentumBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_SHOW_DATA, showMomentum); + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_DRAW_TYPE, bearishMomentumDrawType); + + // + PlotIndexSetDouble(bearishMomentumBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishMomentumBufferIndex, PLOT_ARROW, bearishMomentumArrowCode); + + // + // Bullish Rejection ... + + // + ENUM_DRAW_TYPE bullishRejectionDrawType = showRejection ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishRejectionBuffer, true); + SetIndexBuffer(bullishRejectionBufferIndex, bullishRejectionBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_SHOW_DATA, showRejection); + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_DRAW_TYPE, bullishRejectionDrawType); + + // + PlotIndexSetDouble(bullishRejectionBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishRejectionBufferIndex, PLOT_ARROW, bullishRejectionArrowCode); + + // + // Bearish Rejection ... + + // + ENUM_DRAW_TYPE bearishRejectionDrawType = showRejection ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishRejectionBuffer, true); + SetIndexBuffer(bearishRejectionBufferIndex, bearishRejectionBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_SHOW_DATA, showRejection); + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_DRAW_TYPE, bearishRejectionDrawType); + + // + PlotIndexSetDouble(bearishRejectionBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishRejectionBufferIndex, PLOT_ARROW, bearishRejectionArrowCode); + + // + // Bullish Pin ... + + // + ENUM_DRAW_TYPE bullishPinDrawType = showPin ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishPinBuffer, true); + SetIndexBuffer(bullishPinBufferIndex, bullishPinBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_SHOW_DATA, showPin); + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_DRAW_TYPE, bullishPinDrawType); + + // + PlotIndexSetDouble(bullishPinBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishPinBufferIndex, PLOT_ARROW, bullishPinArrowCode); + + // + // Bearish Pin ... + + // + ENUM_DRAW_TYPE bearishPinDrawType = showPin ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishPinBuffer, true); + SetIndexBuffer(bearishPinBufferIndex, bearishPinBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_SHOW_DATA, showPin); + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_DRAW_TYPE, bearishPinDrawType); + + // + PlotIndexSetDouble(bearishPinBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishPinBufferIndex, PLOT_ARROW, bearishPinArrowCode); + + // + // Bullish Engulf ... + + // + ENUM_DRAW_TYPE bullishEngulfDrawType = showEngulf ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bullishEngulfBuffer, true); + SetIndexBuffer(bullishEngulfBufferIndex, bullishEngulfBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_SHOW_DATA, showEngulf); + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_DRAW_TYPE, bullishEngulfDrawType); + + // + PlotIndexSetDouble(bullishEngulfBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bullishEngulfBufferIndex, PLOT_ARROW, bullishEngulfArrowCode); + + // + // Bearish Engulf ... + + // + ENUM_DRAW_TYPE bearishEngulfDrawType = showEngulf ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(bearishEngulfBuffer, true); + SetIndexBuffer(bearishEngulfBufferIndex, bearishEngulfBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_SHOW_DATA, showEngulf); + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_DRAW_TYPE, bearishEngulfDrawType); + + // + PlotIndexSetDouble(bearishEngulfBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(bearishEngulfBufferIndex, PLOT_ARROW, bearishEngulfArrowCode); + + // + // Swing Low ... + + // + ENUM_DRAW_TYPE swingLowDrawType = showSwing ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingLowBuffer, true); + SetIndexBuffer(swingLowBufferIndex, swingLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingLowBufferIndex, PLOT_SHOW_DATA, showSwing); + PlotIndexSetInteger(swingLowBufferIndex, PLOT_DRAW_TYPE, swingLowDrawType); + + // + PlotIndexSetDouble(swingLowBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingLowBufferIndex, PLOT_ARROW, swingLowArrowCode); + + // + // Swing High ... + + // + ENUM_DRAW_TYPE swingHighDrawType = showSwing ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(swingHighBuffer, true); + SetIndexBuffer(swingHighBufferIndex, swingHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(swingHighBufferIndex, PLOT_SHOW_DATA, showSwing); + PlotIndexSetInteger(swingHighBufferIndex, PLOT_DRAW_TYPE, swingHighDrawType); + + // + PlotIndexSetDouble(swingHighBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(swingHighBufferIndex, PLOT_ARROW, swingHighArrowCode); + + // + // DATA Buffers ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(adxBuffer, true); + SetIndexBuffer(adxBufferIndex, adxBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculatedPOIs( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateValues( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + maBuffer[barIndex] = 0; + atrBuffer[barIndex] = 0; + adxBuffer[barIndex] = 0; + longSLBuffer[barIndex] = 0; + shortSLBuffer[barIndex] = 0; + upTrendBuffer[barIndex] = 0; + swingLowBuffer[barIndex] = 0; + swingHighBuffer[barIndex] = 0; + downTrendBuffer[barIndex] = 0; + bullishPinBuffer[barIndex] = 0; + bearishPinBuffer[barIndex] = 0; + bullishEngulfBuffer[barIndex] = 0; + bearishEngulfBuffer[barIndex] = 0; + bullishMomentumBuffer[barIndex] = 0; + bearishMomentumBuffer[barIndex] = 0; + bullishRejectionBuffer[barIndex] = 0; + bearishRejectionBuffer[barIndex] = 0; +} + +/** + * Calculate Vales ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateValues( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Prepare Requirements ... + + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!isInited) + { + // + iBar.Clean(); + return; + } + + // + XOHCL pBar; + isInited = iBar.GetPreviousBar(pBar); + if (!isInited) + { + // + iBar.Clean(); + pBar.Clean(); + return; + } + int pIndex = pBar.Index(); + + // + // Calculate Applied Price ... + double iPrice = GetAppliedPrice( + appliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + double iMa = maBuffer[bar_index]; + double iMaPrev = maBuffer[pIndex]; + double iAtr = atrBuffer[bar_index]; + double iAdx = adxBuffer[bar_index]; + double iAppliedAtr = iAtr * atrMultiplier; + + // + double points = GetPoints(_Symbol); + double points10 = 10 * points; + + // + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + // SL Buffers ... + + // + double iLongSL = iPrice - iAppliedAtr; + double iShortSL = iPrice + iAppliedAtr; + + // + longSLBuffer[bar_index] = iLongSL; + shortSLBuffer[bar_index] = iShortSL; + + // + // Trend Buffers ... + + // + bool isUpTrend = + // + iPrice > iMa && + iBar.low < iMa && + iAdx > adxThreshold + // + ; + + // + bool isDownTrend = + // + iPrice < iMa && + iBar.high > iMa && + iAdx > adxThreshold + // + ; + + // + double upTrendValue = 0; + double downTrendValue = 0; + if (isUpTrend) + { + upTrendValue = iBar.low; + } + if (isDownTrend) + { + downTrendValue = iBar.high; + } + + // + upTrendBuffer[bar_index] = upTrendValue; + downTrendBuffer[bar_index] = downTrendValue; + + // + // Momentum Buffers ... + + // + bool isMomentum = mXWZBarAnalyser + .IsMomentumBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishMomentum = + isMomentum && + IsBullish(iDir); + bool isBearishMomentum = + isMomentum && + IsBearish(iDir); + if (isMomentum) + { + // + double iBullMomentumValue = 0; + double iBearMomentumValue = 0; + + // + if (isBullishMomentum) + { + // + double selectedValue = iBar.low; + + // + iBullMomentumValue = selectedValue; + } + + // + if (isBearishMomentum) + { + // + double selectedValue = iBar.high; + + // + iBearMomentumValue = selectedValue; + } + + // + bullishMomentumBuffer[bar_index] = iBullMomentumValue; + bearishMomentumBuffer[bar_index] = iBearMomentumValue; + } + + // + // Rejection Buffers ... + + // + bool isRejection = mXWZBarAnalyser + .IsRejectionBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishRejection = + isRejection && + IsBullish(iDir); + bool isBearishRejection = + isRejection && + IsBearish(iDir); + if (isRejection) + { + // + double iBullRejectionValue = 0; + double iBearRejectionValue = 0; + + // + if (isBullishRejection) + { + // + double selectedValue = iBar.low; + + // + iBullRejectionValue = selectedValue; + } + + // + if (isBearishRejection) + { + // + double selectedValue = iBar.high; + + // + iBearRejectionValue = selectedValue; + } + + // + bullishRejectionBuffer[bar_index] = iBullRejectionValue; + bearishRejectionBuffer[bar_index] = iBearRejectionValue; + } + + // + // Pin Buffers ... + + // + bool isPin = mXWZBarAnalyser + .IsPinBar( + iBar, + iDir, + 0, // Extends ... + 50, // Shadow Percent ... + 25 // Body Percent ... + ); + bool isBullishPin = + isPin && + IsBullish(iDir); + bool isBearishPin = + isPin && + IsBearish(iDir); + if (isPin) + { + // + double iBullPinValue = 0; + double iBearPinValue = 0; + + // + if (isBullishPin) + { + // + double selectedValue = iBar.low; + + // + iBullPinValue = selectedValue; + } + + // + if (isBearishPin) + { + // + double selectedValue = iBar.high; + + // + iBearPinValue = selectedValue; + } + + // + bullishPinBuffer[bar_index] = iBullPinValue; + bearishPinBuffer[bar_index] = iBearPinValue; + } + + // + // Engulf Buffers ... + + // + bool isEngulf = mXWZBarAnalyser + .IsEngulfBar( + iBar, + iDir, + 1, // Extends ... + 70 // Body Percent ... + ); + bool isBullishEngulf = + isEngulf && + IsBullish(iDir); + bool isBearishEngulf = + isEngulf && + IsBearish(iDir); + if (isEngulf) + { + // + double iBullEngulfValue = 0; + double iBearEngulfValue = 0; + + // + if (isBullishEngulf) + { + // + double selectedValue = iBar.low; + + // + iBullEngulfValue = selectedValue; + } + + // + if (isBearishEngulf) + { + // + double selectedValue = iBar.high; + + // + iBearEngulfValue = selectedValue; + } + + // + bullishEngulfBuffer[bar_index] = iBullEngulfValue; + bearishEngulfBuffer[bar_index] = iBearEngulfValue; + } + + // + // Swing Buffers ... + + // + bool isSwing = mXWZBarAnalyser + .IsSwing( + iBar, + iDir, + 2 // Range ... + ); + bool isSwingLow = + isSwing && + IsBullish(iDir); + bool isSwingHigh = + isSwing && + IsBearish(iDir); + if (isSwing) + { + // + double iSwingLowValue = 0; + double iSwingHighValue = 0; + + // + if (isSwingLow) + { + // + double selectedValue = iBar.low; + + // + iSwingLowValue = selectedValue; + } + + // + if (isSwingHigh) + { + // + double selectedValue = iBar.high; + + // + iSwingHighValue = selectedValue; + } + + // + swingLowBuffer[bar_index] = iSwingLowValue; + swingHighBuffer[bar_index] = iSwingHighValue; + } + + // + // Cleanup Resources ... + + // + iBar.Clean(); + pBar.Clean(); +} + +// +// POIS Functions ... + +// +void ConfigurePOIDrawer() +{ + // + if (mXWZPOIDrawer == NULL) + { + return; + } + + // + mXWZPOIDrawer.Prefix(ShortName); + mXWZPOIDrawer.ChartIdentification(ChartID()); + mXWZPOIDrawer.SubWindowIdentification(0); + + // + mXWZPOIDrawer.BullishFVGWidth(2); + mXWZPOIDrawer.BullishFVGStyle(STYLE_DOT); + mXWZPOIDrawer.BullishFVGColor(clrAqua); + + // + mXWZPOIDrawer.BearishFVGWidth(2); + mXWZPOIDrawer.BearishFVGStyle(STYLE_DOT); + mXWZPOIDrawer.BearishFVGColor(clrMagenta); + + // + mXWZPOIDrawer.SupportZoneWidth(1); + mXWZPOIDrawer.SupportZoneStyle(STYLE_DASHDOTDOT); + mXWZPOIDrawer.SupportZoneColor(clrLime); + + // + mXWZPOIDrawer.ResistanceZoneWidth(1); + mXWZPOIDrawer.ResistanceZoneStyle(STYLE_DASHDOTDOT); + mXWZPOIDrawer.ResistanceZoneColor(clrRed); + + // + mXWZPOIDrawer.BullishOrderBlockWidth(3); + mXWZPOIDrawer.BullishOrderBlockStyle(STYLE_DASH); + mXWZPOIDrawer.BullishOrderBlockColor(clrAqua); + + // + mXWZPOIDrawer.BearishOrderBlockWidth(3); + mXWZPOIDrawer.BearishOrderBlockStyle(STYLE_DASH); + mXWZPOIDrawer.BearishOrderBlockColor(clrMagenta); +} + +// +void ConfigureAlert() +{ + // + mXWZAlert.SetPrefix(ShortName); + + // + mXWZAlert.SetPushAlerts(mXWZPushAlerts); + mXWZAlert.SetMailAlerts(mXWZMailAlerts); + mXWZAlert.SetEnableAlerts(mXWZEnableAlerts); + mXWZAlert.SetTerminalAlerts(mXWZTerminalAlerts); +} + +// +void CalculatedPOIs( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!isInited) + { + // + iBar.Clean(); + return; + } + + // + XOHCL pBar; + isInited = iBar.GetPreviousBar(pBar); + if (!isInited) + { + // + iBar.Clean(); + pBar.Clean(); + return; + } + + // + // POI ... + DetectPOIs(iBar); + UpdatePOIs(iBar); + DrawPOIs(); + + // + iBar.Clean(); + pBar.Clean(); +} + +// +bool CanDetectPOIs() +{ + // + bool result = false; + + // + result = + // + mXWZDetectOrderBlocks || + mXWZDetectFairValueGaps || + mXWZDetectSupplyZones || + mXWZDetectDemandZones + // + ; + + // + return result; +} + +// +void DetectPOIs( + XOHCL &bar // +) +{ + // + if (!CanDetectPOIs()) + { + return; + } + + // + int barIndex = bar.Index(); + + // + if (barIndex <= 0) + { + return; + } + + // + DetectOrderBlock(bar); + DetectSupplyZone(bar); + DetectDemandZone(bar); + DetectFairValueGap(bar); + + // +} + +// +void UpdatePOIs( + XOHCL &bar // +) +{ + // + int count = 0; + bool has = false; + + // + // OrderBlock(s) ... + + // + has = HasChild(mXWZUnActivatedOBs); + if (has) + { + // + SpecifiedUpdateTo( + mXWZUnActivatedOBs, + bar.time // + ); + } + + // + // Fair Value Gaps ... + + // + has = HasChild(mXWZUnActivatedFVGs); + if (has) + { + // + SpecifiedUpdateTo( + mXWZUnActivatedFVGs, + bar.time // + ); + + // + count = ArraySize(mXWZUnActivatedFVGs); + } + + // + // Supply Zones ... + + // + has = HasChild(mXWZUnActivatedSupplyZones); + if (has) + { + // + SpecifiedUpdateTo( + mXWZUnActivatedSupplyZones, + bar.time // + ); + + // + count = ArraySize(mXWZUnActivatedSupplyZones); + } + + // + // Demand Zones ... + + // + has = HasChild(mXWZUnActivatedDemandZones); + if (has) + { + // + SpecifiedUpdateTo( + mXWZUnActivatedDemandZones, + bar.time // + ); + + // + count = ArraySize(mXWZUnActivatedDemandZones); + } +} + +// +void DrawPOIs() +{ + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + if (!showPOIs) + { + return; + } + + // + // Order Blocks ... + if (showOrderBlocks) + { + // + bool showBullishOrderBlocks = true; + bool showBearishOrderBlocks = true; + + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedOBs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + bool isBullish = mXWZUnActivatedOBs[i].IsBullish(); + + // + if ((isBullish && + showBullishOrderBlocks) || + (!isBullish && + showBearishOrderBlocks)) + { + // + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateOrderBlock( + mXWZUnActivatedOBs[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // + // Fair Value Gaps ... + if (showFairValueGaps) + { + // + bool showBullishFairValueGaps = true; + bool showBearishFairValueGaps = true; + + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedFVGs); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + bool isBullish = mXWZUnActivatedFVGs[i].IsBullish(); + + // + if ((isBullish && + showBullishFairValueGaps) || + (!isBullish && + showBearishFairValueGaps)) + { + // + XCBaseObject *iObj; + isCreated = mXWZPOIDrawer + .CreateFairValueGap( + mXWZUnActivatedFVGs[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + } + } + + // + // Supply Zones ... + if (showSupplyZones) + { + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedSupplyZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateSupplyZone( + mXWZUnActivatedSupplyZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + + // + // Activated ... + count = ArraySize(mXWZActivatedSupplyZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + } + } + } + + // + // Demand Zones ... + if (showDemandZones) + { + // + // UnActivated ... + count = ArraySize(mXWZUnActivatedDemandZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZoneObject *iObj; + isCreated = mXWZPOIDrawer + .CreateDemandZone( + mXWZUnActivatedDemandZones[i], + iObj // + ); + if (isCreated) + { + mXWZDrawnObjects.Add(iObj); + } + } + } + + // + // Activated ... + count = ArraySize(mXWZActivatedDemandZones); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + } + } + } + + // + ChartRedraw(); + + // +} + +// +// +// + +// +// Detect Order Block ... +void DetectOrderBlock(XOHCL &bar) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (!mXWZDetectOrderBlocks) + { + return; + } + + // + int iBarIndex = bar.Index(orderBlockTF); + + // + XOHCL iBar; + bool isInited = iBar.Init( + bar.symbol, + orderBlockTF, + iBarIndex // + ); + if (!isInited) + { + return; + } + + // + XOHCL zoneBar; + ENUM_X_DIRECTION zoneDir; + has = mXWZBarAnalyser.HasOrderBlock( + iBar, + zoneBar, + zoneDir, + mXWZOBFVGSameBars // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + return; + } + + // + XCOrderBlock *zone; + zone = new XCOrderBlock(); + has = zone.Init( + zoneBar, + zoneDir // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Check Start ... + if (mXWZForceStarteds) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone.IsStarted( + zoneDir, + startedBar, + isBodyOut, + iBar.period // + ); + + // + has = isStarted; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + startedBar.Clean(); + + // + return; + } + + // + startedBar.Clean(); + } + + // + // Check Activation ... + if (mXWZForceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = zone.IsActivated( + zoneDir, + activationBar, + isActivationBarBodyIn, + false, + iBar.period // + ); + + // + has = !isActivated; + if (!has) + { + // + if (!mXWZIgnoreUnActivateds) + { + // + zone.To(activationBar.time); + + // + Add( + zone, + mXWZActivatedOBs // + ); + } + + // + zoneBar.Clean(); + ZeroMemory(zone); + activationBar.Clean(); + + // + return; + } + + // + activationBar.Clean(); + } + + // + // Check Breaktion ... + if (mXWZForceUnBreaked) + { + // + XOHCL breakedBar; + bool isBodyOut = false; + bool isBreaked = zone.IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, + iBar.period // + ); + + // + has = !isBreaked; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + breakedBar.Clean(); + + // + return; + } + + // + breakedBar.Clean(); + } + + // + // Check Indexes ... + + // + // UnActivateds ... + idx = FindIndex( + zone, + mXWZUnActivatedOBs // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Activateds ... + idx = FindIndex( + zone, + mXWZActivatedOBs // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + has = zone != NULL && + zone.IsValid(); + if (has) + { + // + zone.To(bar.time); + + // + Add( + zone, + mXWZUnActivatedOBs // + ); + } + + // + iBar.Clean(); + zoneBar.Clean(); +} + +// +// Detect Fair Value Gap ... +void DetectFairValueGap(XOHCL &bar) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (!mXWZDetectFairValueGaps) + { + return; + } + + // + int iBarIndex = bar.Index(fairValueGapTF); + + // + XOHCL iBar; + bool isInited = iBar.Init( + bar.symbol, + fairValueGapTF, + iBarIndex // + ); + if (!isInited) + { + return; + } + + // + XOHCL zoneEndBar; + XOHCL zoneStartBar; + ENUM_X_DIRECTION zoneDir; + has = mXWZBarAnalyser.HasFairValueGap( + iBar, + zoneStartBar, + zoneEndBar, + zoneDir, + mXWZOBFVGSameBars // + ); + + // + if (!has) + { + // + zoneEndBar.Clean(); + zoneStartBar.Clean(); + return; + } + + // + XCFVG *zone; + zone = new XCFVG(); + has = zone.Init( + zoneStartBar, + zoneEndBar, + zoneDir // + ); + + // + if (!has) + { + // + ZeroMemory(zone); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + + // + return; + } + + // + // Check Start ... + if (mXWZForceStarteds) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone.IsStarted( + zoneDir, + startedBar, + isBodyOut, + iBar.period // + ); + + // + has = isStarted; + if (!has) + { + // + ZeroMemory(zone); + startedBar.Clean(); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + + // + return; + } + + // + startedBar.Clean(); + } + + // + // Check Activation ... + if (mXWZForceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = zone.IsActivated( + zoneDir, + activationBar, + isActivationBarBodyIn, + false, + iBar.period // + ); + + // + has = !isActivated; + if (!has) + { + // + ZeroMemory(zone); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + activationBar.Clean(); + + // + return; + } + + // + activationBar.Clean(); + } + + // + // Check Breaktion ... + if (mXWZForceUnBreaked) + { + // + XOHCL breakedBar; + bool isBodyOut = false; + bool isBreaked = zone.IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, + iBar.period // + ); + + // + has = !isBreaked; + if (!has) + { + // + ZeroMemory(zone); + breakedBar.Clean(); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + + // + return; + } + + // + breakedBar.Clean(); + } + + // + // Check Indexes ... + + // + // UnActivateds ... + idx = FindIndex( + zone, + mXWZUnActivatedFVGs // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + ZeroMemory(zone); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + + // + return; + } + + // + // Activateds ... + idx = FindIndex( + zone, + mXWZActivatedFVGs // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + ZeroMemory(zone); + zoneEndBar.Clean(); + zoneStartBar.Clean(); + + // + return; + } + + // + has = zone != NULL && + zone.IsValid(); + if (has) + { + // + zone.To(bar.time); + + // + Add( + zone, + mXWZUnActivatedFVGs // + ); + } + + // + iBar.Clean(); + zoneEndBar.Clean(); + zoneStartBar.Clean(); +} + +// +// Supply Zone ... +void DetectSupplyZone(XOHCL &bar) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (!mXWZDetectSupplyZones) + { + return; + } + + // + int iBarIndex = bar.Index(supDemTF); + + // + XOHCL iBar; + bool isInited = iBar.Init( + bar.symbol, + supDemTF, + iBarIndex // + ); + if (!isInited) + { + return; + } + + // + int range = mXWZSuResRange * 2; + + // + XOHCL zoneBar; + ENUM_X_DIRECTION zoneDir = X_DIRECTION_BEARISH; + has = mXWZBarAnalyser.HasResistance( + iBar, + zoneBar, + range // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + return; + } + + // + XCSupplyZone *zone; + zone = new XCSupplyZone(); + has = zone.Init( + zoneBar, + range, + true // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Check Start ... + if (mXWZForceStarteds) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone.IsStarted( + zoneDir, + startedBar, + isBodyOut, + iBar.period // + ); + + // + has = isStarted; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + startedBar.Clean(); + + // + return; + } + + // + startedBar.Clean(); + } + + // + // Check Activation ... + if (mXWZForceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = zone.IsActivated( + zoneDir, + activationBar, + isActivationBarBodyIn, + false, + iBar.period // + ); + + // + has = !isActivated; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + activationBar.Clean(); + + // + return; + } + + // + activationBar.Clean(); + } + + // + // Check Breaktion ... + if (mXWZForceUnBreaked) + { + // + XOHCL breakedBar; + bool isBodyOut = false; + bool isBreaked = zone.IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, + iBar.period // + ); + + // + has = !isBreaked; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + breakedBar.Clean(); + + // + return; + } + + // + breakedBar.Clean(); + } + + // + // Check Indexes ... + + // + // UnActivateds ... + idx = FindIndex( + zone, + mXWZUnActivatedSupplyZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Activateds ... + idx = FindIndex( + zone, + mXWZActivatedSupplyZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + has = zone != NULL && + zone.IsValid(); + if (has) + { + // + zone.To(bar.time); + + // + Add( + zone, + mXWZUnActivatedSupplyZones // + ); + } + + // + iBar.Clean(); + zoneBar.Clean(); +} + +// +// Demand Zone ... +void DetectDemandZone(XOHCL &bar) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + if (!mXWZDetectDemandZones) + { + return; + } + + // + int iBarIndex = bar.Index(supDemTF); + + // + XOHCL iBar; + bool isInited = iBar.Init( + bar.symbol, + supDemTF, + iBarIndex // + ); + if (!isInited) + { + return; + } + + // + int range = mXWZSuResRange * 2; + + // + XOHCL zoneBar; + ENUM_X_DIRECTION zoneDir = X_DIRECTION_BULLISH; + has = mXWZBarAnalyser.HasSupport( + iBar, + zoneBar, + range // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + return; + } + + // + XCDemandZone *zone; + zone = new XCDemandZone(); + has = zone.Init( + zoneBar, + range, + true // + ); + + // + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Check Start ... + if (mXWZForceStarteds) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = zone.IsStarted( + zoneDir, + startedBar, + isBodyOut, + iBar.period // + ); + + // + has = isStarted; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + startedBar.Clean(); + + // + return; + } + + // + startedBar.Clean(); + } + + // + // Check Activation ... + if (mXWZForceActivation) + { + // + XOHCL activationBar; + bool isActivationBarBodyIn = false; + bool isActivated = zone.IsActivated( + zoneDir, + activationBar, + isActivationBarBodyIn, + false, + iBar.period // + ); + + // + has = !isActivated; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + activationBar.Clean(); + + // + return; + } + + // + activationBar.Clean(); + } + + // + // Check Breaktion ... + if (mXWZForceUnBreaked) + { + // + XOHCL breakedBar; + bool isBodyOut = false; + bool isBreaked = zone.IsBreaked( + zoneDir, + breakedBar, + isBodyOut, + false, + iBar.period // + ); + + // + has = !isBreaked; + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + breakedBar.Clean(); + + // + return; + } + + // + breakedBar.Clean(); + } + + // + // Check Indexes ... + + // + // UnActivateds ... + idx = FindIndex( + zone, + mXWZUnActivatedDemandZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + // Activateds ... + idx = FindIndex( + zone, + mXWZActivatedDemandZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + zoneBar.Clean(); + ZeroMemory(zone); + + // + return; + } + + // + has = zone != NULL && + zone.IsValid(); + if (has) + { + // + zone.To(bar.time); + + // + Add( + zone, + mXWZUnActivatedDemandZones // + ); + } + + // + iBar.Clean(); + zoneBar.Clean(); +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Libraries/x-saherelm.common.lib.ex5 b/BKPS/14031218/Libraries/x-saherelm.common.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..b843f895bdaeebc2d2afc3a951b9241ec7f10359 GIT binary patch literal 5520 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 + +// +// Models ... + +// +// Specified Price Type ... +enum ENUM_X_PRICE +{ + X_PRICE_HIGH, + X_PRICE_OPEN, + X_PRICE_CLOSE, + X_PRICE_LOW, + X_PRICE_UP, + X_PRICE_DOWN +}; + +// +enum ENUM_X_DIRECTION +{ + X_DIRECTION_ALL, // All + X_DIRECTION_NONE, // None + X_DIRECTION_BULLISH, // Bullish + X_DIRECTION_BEARISH, // Bearish +}; + +// +enum ENUM_X_FIBO_LEVELS +{ + X_FIBO_LEVEL_236, + X_FIBO_LEVEL_382, + X_FIBO_LEVEL_500, + X_FIBO_LEVEL_618, + X_FIBO_LEVEL_764, +}; + +// +double GetFiboLevelValue(ENUM_X_FIBO_LEVELS value) +{ + // + double result = 0; + + // + switch (value) + { + // + case X_FIBO_LEVEL_236: + result = 0.236; + break; + + // + case X_FIBO_LEVEL_382: + result = 0.382; + break; + + // + case X_FIBO_LEVEL_500: + result = 0.500; + break; + + // + case X_FIBO_LEVEL_618: + result = 0.618; + break; + + // + case X_FIBO_LEVEL_764: + result = 0.764; + break; + } + + // + return result; +} + +// +string ToString(ENUM_X_DIRECTION value) +{ + // + string result = NULL; + + // + switch (value) + { + case X_DIRECTION_ALL: + result = "ALL"; + break; + case X_DIRECTION_NONE: + result = "NONE"; + break; + case X_DIRECTION_BULLISH: + result = "BULLISH"; + break; + case X_DIRECTION_BEARISH: + result = "BEARISH"; + break; + } + + // + return result; +} + +// +// Swing Types Enum ... +enum ENUM_X_SWING_TYPE +{ + X_NO_SWING = 0, + X_SWING_HIGH = 1, + X_SWING_LOW = -1, +}; + +// +string ToString(ENUM_X_SWING_TYPE value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_NO_SWING: + result = "NO_SWING"; + break; + + // + case X_SWING_LOW: + result = "SWING_LOW"; + break; + + // + case X_SWING_HIGH: + result = "SWING_HIGH"; + break; + } + + // + return result; +} + +// +ENUM_SERIESMODE ToSeriesMode(ENUM_X_SWING_TYPE value) +{ + // + ENUM_SERIESMODE result = MODE_HIGH; + + // + switch (value) + { + // + case X_SWING_HIGH: + result = MODE_HIGH; + break; + + // + case X_SWING_LOW: + result = MODE_LOW; + break; + } + + // + return result; +} + +// +// Find Swing Points ... +int FindSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_X_SWING_TYPE mMode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (StringLen(mSymbol) == 0 || (mMode != X_SWING_HIGH && mMode != X_SWING_LOW)) + { + return result; + } + + // + int current = bar_index; + int founded = FindNextSwing( + mSymbol, + mPeriod, + mMode, + (mLength * 2) + 1, + current - mLength); + + // + while (founded != current) + { + // + current = FindNextSwing( + mSymbol, + mPeriod, + mMode, + mLength, + current + 1); + + // + founded = FindNextSwing( + mSymbol, + mPeriod, + mMode, + (mLength * 2) + 1, + current - mLength); + } + + // + result = current; + + // + return result; +} + +// +// Find Next Swing ... +int FindNextSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_X_SWING_TYPE mMode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (bar_index < 0) + { + mLength += bar_index; + bar_index = 0; + } + + // + ENUM_SERIESMODE mSeriesMode = ToSeriesMode(mMode); + + // + result = mMode == X_SWING_HIGH + ? iHighest( + mSymbol, + mPeriod, + mSeriesMode, + mLength, + bar_index) + : iLowest( + mSymbol, + mPeriod, + mSeriesMode, + mLength, + bar_index); + + // + return result; +} + +// +// XPERIOD Calculation Method ... +enum ENUM_X_PERIOD_METHOD +{ + // + X_PERIOD_NOTHING, // Nothing + X_PERIOD_AUTO, // Auto Select + X_PERIOD_MANUALLY // Manually +}; + +// +// Available Market Cycles ... +enum ENUM_X_MARKET_CYCLES +{ + // + X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle + X_MARKET_CYCLE_SHORT, // Short Cycle + X_MARKET_CYCLE_MEDIUM, // Medium Cycle + X_MARKET_CYCLE_LONG, // Long Cycle + X_MARKET_CYCLE_HIND, // Hind Cycle +}; + +// +// Structs ... + +// +// Model Specified Ticks Info ... +struct XTick +{ + // + string symbol; // Symbol ... + datetime time; // Time ... + double bid; // Bid ... + double ask; // Ask ... + double spread; // Spread ... + long volume; // Volume ... + + // + // Constructor ... + void XTick() + { + Clean(); + } + + // + // Tools Functions ... + + /** + * Initial ... + * + * @param _symbol: Symbol ... + * @param _time: Time ... + * @param _bid: Bid Price ... + * @param _ask: Ask Price ... + * @param _volume: Tick Volume ... + */ + bool Init( + string _symbol, + datetime _time, + double _bid, + double _ask, + double _spread, + long _volume // + ) + { + // + bool result = false; + + // + result = IsValid(_symbol) && + IsValid(_time) && + _bid > 0 && + _ask > 0; + if (!result) + { + return result; + } + + // + bid = _bid; + ask = _ask; + time = _time; + symbol = _symbol; + spread = _spread; + + // + result = IsValid(); + + // + return result; + } + + /** + * Init Tick by Symbol ... + * + * @param _symbol: String ... + * + * @return ( bool ) + */ + bool Init( + string _symbol, + ENUM_TIMEFRAMES _volumePeriod = NULL // + ) + { + // + bool result = false; + + // + result = IsValid(_symbol); + if (!result) + { + return result; + } + + // + datetime _time = TimeCurrent(); + double _bid = GetBid(_symbol); + double _ask = GetAsk(_symbol); + double _spread = GetSpread(_symbol); + + // + long _volume = 0; + if (IsValid(_volumePeriod)) + { + _volume = iTickVolume(_symbol, _volumePeriod, 0); + } + + // + result = Init( + _symbol, + _time, + _bid, + _ask, + _spread, + _volume // + ); + + // + return result; + } + + /** + * Cleanup ... + */ + void Clean() + { + // + bid = 0; + ask = 0; + volume = 0; + time = NULL; + symbol = NULL; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol) && + IsValid(time) && + bid > 0 && + ask > 0 && + volume >= 0; + + // + return result; + } + + // +}; + +// +// Model a Bar Remains Time ... +struct XBarRemainsTime +{ + // + int days; + int hours; + int minutes; + int seconds; + + // + // Constructor ... + XBarRemainsTime() + { + Clean(); + } + + // + // Always Calculate Current 0 Bar Timing ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetBarTime( + mSymbol, + mPeriod, + 0 + // + ); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + days = 0; + hours = 0; + minutes = 0; + seconds = 0; + + // + ZeroMemory(this); + } + + // + // To String Representation ... + string ToString( + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true + // + ) + { + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || days > 0) + { + result += dayId + idSeparator + (string)days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || hours > 0) + { + // + string strHour = ToString(hours); + if (StringLen(strHour) == 1) + { + strHour = "0" + strHour; + } + + // + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || minutes > 0) + { + // + string strMinute = ToString(minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || seconds > 0) + { + // + string strSec = ToString(seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; + } +}; + +// +// Describe an Specific Candle ... +struct XOHCL +{ + // + // Props ... + + // + double high; + double open; + double close; + double low; + + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOHCL() + { + Clean(); + } + + // + // Init a Bar ... + // Using Bar Index ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex // + ); + + // + open = iOpen( + mSymbol, + mPeriod, + barIndex // + ); + open = NormalizePrice(open, mSymbol); + + // + close = iClose( + mSymbol, + mPeriod, + barIndex // + ); + close = NormalizePrice(close, mSymbol); + + // + high = iHigh( + mSymbol, + mPeriod, + barIndex // + ); + high = NormalizePrice(high, mSymbol); + + // + low = iLow( + mSymbol, + mPeriod, + barIndex // + ); + low = NormalizePrice(low, mSymbol); + + // + bool result = IsValid(); + + // + return result; + } + + // + // Init a Bar ... + // Using Bar Time ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + datetime mTime = NULL // Bar Time + ) + { + // + mTime = NormalizeTime(mTime); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + bool result = Init( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; + } + + // + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + double mOpen = 0, // Open + double mHigh = 0, // High + double mClose = 0, // Close + double mLow = 0, // Low + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = mOpen; + high = mHigh; + close = mClose; + low = mLow; + + // + return IsValid(); + } + + // + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + double mOpen = 0, // Open + double mHigh = 0, // High + double mClose = 0, // Close + double mLow = 0, // Low + datetime mTime = NULL // Bar Time + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + int barIndex = iBarShift( + symbol, + period, + mTime); + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = mOpen; + high = mHigh; + close = mClose; + low = mLow; + + // + return IsValid(); + } + + // + // Tools ... + + // + void Clean() + { + // + high = 0; + open = 0; + close = 0; + low = 0; + + // + time = NULL; + symbol = NULL; + period = NULL; + + // + ZeroMemory(this); + } + + // + // Validate Bar ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + high > 0 && + open > 0 && + close > 0 && + low > 0 + // + ; + + // + return result; + } + + // + int TotalBars() + { + // + int result = 0; + + // + result = iBars( + symbol, + period // + ); + + // + return result; + } + + // + // Calculate X_PRICE Specified Type ... + double GetPrice(ENUM_X_PRICE mPType) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + switch (mPType) + { + // + case X_PRICE_OPEN: + result = open; + break; + // + case X_PRICE_HIGH: + result = high; + break; + // + case X_PRICE_CLOSE: + result = close; + break; + // + case X_PRICE_LOW: + result = low; + break; + // + case X_PRICE_UP: + result = GetUp(); + break; + // + case X_PRICE_DOWN: + result = GetDown(); + break; + } + + // + return result; + } + + // + // Retrieve Price base On Series Mode ... + double GetPrice(ENUM_SERIESMODE mMode) + { + // + ENUM_X_PRICE mXMode = ToPrice(mMode); + + // + return GetPrice(mXMode); + } + + // + // Calculate Applied Price ... + double GetPrice( + ENUM_APPLIED_PRICE mAppliedTo // Select Application Method + ) + { + // + double result = 0; + + // + // Calculate Applied Price ... + switch (mAppliedTo) + { + // + case PRICE_CLOSE: + result = close; + break; + + // + case PRICE_OPEN: + result = open; + break; + + // + case PRICE_HIGH: + result = high; + break; + + // + case PRICE_LOW: + result = low; + break; + + // + case PRICE_MEDIAN: + result = (high + low) / 2; + break; + + // + case PRICE_TYPICAL: + result = (high + low + close) / 3; + break; + + // + case PRICE_WEIGHTED: + result = (high + low + close + close) / 4; + break; + } + + // + return result; + } + + // + // Find Specific Price ... + bool FindHigherPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice > price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Find Specific Price ... + bool FindLowerPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice < price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Calculate Bar Mid Line ... + double GetMid() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = (high + low) / 2; + + // + return result; + } + + // + // Calculate up Price ... + double GetUp() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMax(open, close); + + // + return result; + } + + // + // Calculate Down Price ... + double GetDown() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMin(open, close); + + // + return result; + } + + // + // Retrieve Required Price for Zone Checking ... + // For Bullish Zones => low; + // For Bearish Zones => high; + double GetZoneCheckValue(ENUM_X_DIRECTION forDir) + { + // + double result = 0; + + // + if (!IsValid() || + !HasDirection(forDir)) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + result = + isBullish + ? low + : high; + + return result; + } + + // + // Calculate Bar Body ... + double GetBody() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetUp() - GetDown(); + + // + return result; + } + + // + // Calculate Bar Range ... + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = high - low; + + // + return result; + } + + // + // Calculate Bar Shadows ... + double GetShadows() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetRange() - GetBody(); + + // + return result; + } + + // + // Calculate Bar High Shadow ... + double GetHighShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + high - GetUp() + // + ; + + // + return result; + } + + // + // Calculate Bar Low Shadow ... + double GetLowShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetDown() - low; + // + ; + + // + return result; + } + + // + // Check Bar is Bullish ... + bool IsBullish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open < close; + + // + return result; + } + + // + // Check Bar is Bearish ... + bool IsBearish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open > close; + + // + return result; + } + + // + // Get Direction of Bar ... + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + bool isBullish = IsBullish(); + bool isBearish = IsBearish(); + + // + result = + isBullish && isBearish + ? X_DIRECTION_ALL + : !isBullish && !isBearish + ? X_DIRECTION_NONE + : isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Find Next Bar Time ... + datetime NextAt() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time + prSeconds; + + // + return result; + } + + // + // Find Prev Bar Time ... + datetime BeforeOn() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time - prSeconds; + + // + return result; + } + + // + // Calculate Last Bar Open Time in Smaller Period ... + datetime GetLastBarTimeOfPeriod( + ENUM_TIMEFRAMES smallerPeriod // + ) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int sourceSeconds = PeriodSeconds(period); + int destSeconds = PeriodSeconds(smallerPeriod); + if (destSeconds >= sourceSeconds) + { + // + result = time; + return result; + } + + // + result = (datetime)((((int)time) + sourceSeconds) - destSeconds); + + // + return result; + } + + // + // Calculate Close Time ... + datetime GetCloseTime() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int seconds = PeriodSeconds(period); + + // + result = (datetime)(((int)time) + seconds); + + // + return result; + } + + // + bool BarAt( + int index, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + if (index < 0) + { + index = 0; + } + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool BarIn( + ENUM_TIMEFRAMES _period, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid() && + IsSpecifiedValid(_period); + if (!result) + { + return result; + } + + // + int index = Index(_period); + result = bar.Init( + symbol, + _period, + index // + ); + + // + return result; + } + + // + // Find Current Bar Index on Chart ... + int Index() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + time + // + ); + + // + return result; + } + + // + int Index(datetime value) + { + // + int result = -1; + + // + value = NormalizeTime(value); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + value // + ); + + // + return result; + } + + // + int Index(ENUM_TIMEFRAMES value) + { + // + int result = -1; + + // + result = IsValid() && + IsSpecifiedValid(value); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + value, + time // + ); + + // + return result; + } + + // + bool GetNextBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + result = idx > 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + this.symbol, + this.period, + idx - 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + bool GetPreviousBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + + // + result = bar.Init( + this.symbol, + this.period, + idx + 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Find Highest Bar Index ... + int FindHighestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iHighest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Highest ... + double FindHighest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindHighestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iH; + result = iH.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iH.GetPrice(mMode); + + // + return result; + } + + // + // Find Highest ... + double FindHighestUp( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindHighest(mLength, MODE_OPEN); + result = MathMax(mLength, FindHighest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindLowestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iLowest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindLowest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindLowestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iL; + result = iL.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iL.GetPrice(mMode); + + // + return result; + } + + // + // Find Lowest ... + double FindLowesttDown( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindLowest(mLength, MODE_OPEN); + result = MathMax(mLength, FindLowest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Other ... + string GetTag(string prefix = "") + { + // + string result = NULL; + + // + result = + (IsValid(prefix) + ? prefix + "_" + : "") + + "XOHCL_" + symbol + "_" + ToString(period) + "_" + ToFormatString(time); + + // + return result; + } + + // + // Convert to String Representation ... + string ToString() + { + // + string result = ""; + + // + result = GetTypeName(this) + + "(O(" + ToString(open) + "),H(" + ToString(high) + "),C(" + ToString(close) + "),L(" + ToString(low) + "))"; + + // + return result; + } +}; + +// +// Tracking Times ... +struct XTimeTracker +{ + // + // Props ... + int xMonth; + int xDayOfWeek; + int xForWeekDay; + int xDay; + int xHour; + int xMinute; + + // + // Constructor ... + XTimeTracker() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + xDay = -1; + xHour = -1; + xMonth = -1; + xMinute = -1; + xDayOfWeek = -1; + xForWeekDay = -1; + + // + ZeroMemory(this); + } + + // + // Detecting New Minute ... + bool IsNewMinute() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.min != xMinute; + if (result) + { + xMinute = timeStruct.min; + } + + // + return result; + } + + // + // Detecting New Houre ... + bool IsNewHour() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; + } + + // + // Detecting New Day ... + bool IsNewDay() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; + } + + // + // Detecting New Week ... + bool IsNewWeek() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; + } + + // + // Detecting End Of Week ... + bool IsWeekEnd() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; + } + + // + // Detecting New Month ... + bool IsNewMonth() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; + } +}; + +// +// Tracking Bars on Specified Environment ... +struct XBarTracker +{ + // + string symbol; // Tracking Symbol + ENUM_TIMEFRAMES period; // Tracking Time Frame + + // + int lastTrackedBar; // Last Tracked Bar ... + + // + bool waitsUntilNext; // Waits Until Next Bar ... + + // + // Constructor ... + XBarTracker() + { + Clean(); + } + + // + // Initializer ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + this.symbol = mSymbol; + this.period = mPeriod; + + // + this.lastTrackedBar = 0; + + // + result = true; + + // + return result; + } + + // + // Retrieve all Bars ... + int CountBars() + { + // + return iBars( + symbol, + period + // + ); + } + + // + // Check if it's New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + int currentBars = CountBars(); + + // + result = currentBars > lastTrackedBar; + if (result) + { + lastTrackedBar = currentBars; + } + + // + return result; + } + + // + bool CanProcessBar() + { + // + bool _isInTestMode = IsRunningOnTestMode(); + + // + bool isNewBar = IsNewBar(); + + // + bool result = + _isInTestMode + ? isNewBar + : !waitsUntilNext + ? true + : isNewBar; + if (result && waitsUntilNext) + { + waitsUntilNext = false; + } + + // + return result; + } + + // + void Waits() + { + this.waitsUntilNext = true; + } + + // + // Tools ... + void Clean() + { + // + symbol = NormalizeSymbol(NULL); + period = NormalizePeriod(NULL); + + // + ZeroMemory(this); + } + + // + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + NormalizeTime(time); + + // + int barIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + result = barIndex >= 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + barIndex // + ); + + // + return result; + } + + // + int Index(datetime time = NULL) + { + // + int result = 0; + + // + NormalizeTime(time); + + // + result = iBarShift( + symbol, + period, + time, + false // + ); + + // + return result; + } +}; + +// +// Model a Market Cycle ... +struct XMarketCycle +{ + // + // Props ... + + // + string prefix; // Prefix Trag ... + + // + string symbol; // Market Symbol ... + + // + ENUM_TIMEFRAMES period; // Period of Cycle ... + ENUM_X_PERIOD_METHOD method; // Period Selection Method ... + ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ... + + // + int length; // Number Of Candles per Current Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ... + + // + datetime lastStart; // Last Candle Bar Time ... + + // + XBarTracker barTracker; // Bar Tracker ... + XBarRemainsTime remains; // Current Bar Remains Model ... + + // + // Constructor ... + XMarketCycle() + { + Clean(); + } + + // + // Init Cycle ... + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mHostPeriod = NormalizePeriod(mHostPeriod); + + // + result = IsValid(mCycle); + if (!result) + { + return result; + } + + // + this.cycle = mCycle; + + // + // Set Automatically Prefix ... + if (StringLen(mPrefix) == 0) + { + this.prefix = ToString(cycle); + } + + // + result = IsValid( + method, + period // + ); + if (!result) + { + return result; + } + + // + this.symbol = mSymbol; + this.hostPeriod = mHostPeriod; + + // + // Find Cycle Period ... + if (method == X_PERIOD_AUTO) + { + // + // Select Period ... + this.period = GetCyclePeriod( + this.cycle, + this.hostPeriod); + } + + // + // Set Prefix if Provided ... + if (StringLen(mPrefix) > 0) + { + this.prefix = mPrefix; + } + + // + // Calculate Required Info ... + + // + // Length ... + this.length = PeriodSeconds(this.period) / PeriodSeconds(this.hostPeriod); + + // + // Update Additional Data ... + result = this.Update(0); + + // + return result; + } + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + ENUM_X_PERIOD_METHOD mMethod, // Period Selection Method + ENUM_TIMEFRAMES mPeriod, // Provided Period + string mPrefix = "" // Prefix + ) + { + // + this.period = mPeriod; + this.method = mMethod; + + // + return Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + length = 0; + lastStart = 0; + + // + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + method = NULL; + hostPeriod = NULL; + + // + remains.Clean(); + barTracker.Clean(); + + // + ZeroMemory(this); + } + + // + // Check Structure Valid ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid( + method, + period); + if (!result) + { + return result; + } + + // + result = + // + length > 0 && + symbol != NULL && + period != NULL && + method != NULL && + hostPeriod != NULL && + method != X_PERIOD_NOTHING + // + ; + + // + return result; + } + + // + // Update Market Cycle Additional Info ... + bool Update(int hostBarIndex) + { + // + bool result = false; + + // + result = this.IsValid(); + if (!result) + { + return result; + } + + // + // Init Remains ... + result = remains.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + // Init Bar Tracker ... + result = barTracker.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Count Bars ... + int CountBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.CountBars(); + + // + return result; + } + + // + // Check New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.IsNewBar(); + + // + return result; + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + return result; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + // + result = totalBars - 1; + return result; + } + + // + datetime hostBarTime = iTime( + this.symbol, + this.hostPeriod, + barIndex + // + ); + + // + result = iBarShift( + this.symbol, + this.period, + hostBarTime + // + ); + + // + return result; + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + XOHCL result; + result.Init( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Extract Specific Range of Bars ... + // using Start Bar Index ... + int GetBars( + XOHCL &result[], // Hold Result + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + int total = Bars( + symbol, + period); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + symbol, + period, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; + } + + // + // Extract Specific Range of Bars ... + // using Start Bar Time ... + int GetBars( + XOHCL &result[], // Hold Result + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array + ) + { + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( + symbol, + period, + from, + false + // + ); + + // + return GetBars( + result, + symbol, + period, + barIndex, + count, + forceClean + // + ); + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + result = iTime( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Find Chart ID ... + ulong GetChartID() + { + // + ulong result = 0; + + // + long firstChart = ChartFirst(); + result = firstChart; + + // + while (result >= 0) + { + // + string chSymbol = ChartSymbol(result); + ENUM_TIMEFRAMES chPeriod = ChartPeriod(result); + + // + bool isOwnChart = + // + symbol == chSymbol && + period == chPeriod + // + ; + if (isOwnChart) + { + break; + } + + // + result = ChartNext(result); + if (result < 0) + { + break; + } + } + + // + return result; + } + + // + // Create and String Representation for Unique Taging ... + string ToString() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = + GetTypeName(this) + "(" + + "PRFX(" + this.prefix + ")" + + "SMBL(" + this.symbol + ")" + + "CYC(" + ToString(this.cycle) + ")" + + "PRD(" + ToString(this.period) + ")" + + "PRDHST(" + ToString(this.hostPeriod) + ")" + + "MTH(" + EnumToString(this.method) + ")" + + ")"; + + // + return result; + } + + // + // Here we Produce a Summary brief of + // state of Cycle ... + string GenerateSummary() + { + // + string result = ""; + + // + bool hasPrefix = + StringLen(this.prefix) > 0 && + this.prefix != ToString(this.cycle); + result += (hasPrefix ? this.prefix + "[" : "") + + ToString(this.cycle) + + (hasPrefix ? "]" : "") + "\n"; + + // + result += " - PR: " + ToString(this.period) + "\n"; + + // + XOHCL cBar = GetBar(0); + + // + result += " - State: " + (cBar.IsBullish() ? "Bullish" : cBar.IsBearish() ? "Bearish" + : "Neutural"); + + // + return result; + } +}; + +// +// Linear Regression ... + +// +struct XLinearRegressionWorkStruct +{ + // + struct sDataStruct + { + // + double value; + double sumY; + double sumXY; + }; + + // + sDataStruct data[]; + + // + int dataSize; + int period; + double sumX; + double sumXX; + double divisor; + + // + // Constructor ... + XLinearRegressionWorkStruct() + : dataSize(-1), period(-1) + { + } +}; + +// +struct XLinearRegression +{ + // + XLinearRegressionWorkStruct m_work; + + // + // Calculate Linear Regression ... + double Calculate( + double value, + int period, + double &_slope, + double &_intercept, + int r, + int bars // + ) + { + // + if (m_work.dataSize <= bars) + { + m_work.dataSize = ArrayResize(m_work.data, bars + 500, 2000); + } + + // + if (period < 1) + { + period = 1; + } + + // + if (m_work.period != (int)period) + { + // + m_work.period = (int)period; + m_work.sumX = m_work.period * (m_work.period - 1.0) / 2.0; + m_work.sumXX = m_work.period * (m_work.period - 1.0) * (2.0 * m_work.period - 1.0) / 6.0; + m_work.divisor = m_work.sumX * m_work.sumX - m_work.period * m_work.sumXX; + + // + if (m_work.divisor) + { + m_work.divisor = 1.0 / m_work.divisor; + } + } + + // + m_work.data[r].value = value; + + // + if (r >= m_work.period) + { + // + m_work.data[r].sumY = m_work.data[r - 1].sumY + value - m_work.data[r - m_work.period].value; + m_work.data[r].sumXY = m_work.data[r - 1].sumXY + m_work.data[r].sumY - m_work.data[r - m_work.period].value * (m_work.period - 1.0) - value; + } + else + { + // + m_work.data[r].sumY = value; + m_work.data[r].sumXY = 0; + + // + for (int _k = 1; _k < m_work.period && r >= _k; _k++) + { + // + m_work.data[r].sumY += m_work.data[r - _k].value; + m_work.data[r].sumXY += _k * m_work.data[r - _k].value; + } + } + + // + _slope = (m_work.period * m_work.data[r].sumXY - m_work.sumX * m_work.data[r].sumY) * m_work.divisor; + _intercept = (m_work.data[r].sumY - _slope * m_work.sumX) / (double)m_work.period; + + // + double result = (_intercept + _slope * (m_work.period - 1.0)); + + // + return result; + } + + // +}; + +// +// Use To Parse Symbols for +// Ignore Brokers Additional Suffixes ... +struct XSymbolParser +{ + // + string version; // Temp ... + + // + // Symbol Parsing ... + + // + // Forext ... + + // + bool IsEURUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsGBPUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "GBP", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURGBP(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "GBP" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsAUDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "AUD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURAUD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "AUD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsNZDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "NZD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURNZD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "NZD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Metals ... + + // + bool IsXAUUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAU", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsXAGUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAG", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Indexes ... + + // + bool IsDowJones(string symbol) + { + // + bool result = Contains( + "DowJones30", + symbol // + ); + + // + return result; + } + + // + // Oil ... + + // + bool IsBrent(string symbol) + { + // + bool result = Contains( + "BRENT", + symbol // + ); + + // + return result; + } + + // + // Symbol Finder ... + string GetEURUSDSymbol() + { + // + string result = NULL; + + // + string symbols[]; + int symbolsCount = GetAllSymbols( + symbols // + ); + if (!IsValidSize(symbolsCount)) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = symbols[i]; + if (IsEURUSD(iSymbol)) + { + // + result = iSymbol; + break; + } + } + + // + return result; + } +}; + +// +struct XSymbolSessionParser +{ + // + string version; // Temp ... + + // + // Check Market Is Open for Specific Symbol + // in Current Time ... + bool CanTrade( + string symbol // Trading Symbol + ) + { + // + bool result = false; + + // + result = IsValid(symbol); + if (!result) + { + return result; + } + + // + MqlDateTime timeStruct; + result = TimeCurrent(timeStruct); + if (!result) + { + return result; + } + + // + ENUM_DAY_OF_WEEK dayOfWeek = (ENUM_DAY_OF_WEEK)timeStruct.day_of_week; + + // + datetime cTime = TimeCurrent(); + + // + datetime from; + datetime to; + result = SymbolInfoSessionTrade( + symbol, + dayOfWeek, + 0, // Session Index ... + from, + to // + ); + if (!result) + { + return result; + } + + // + result = cTime > from && cTime < to; + + // + return result; + } +}; + +// +// Parsing Market Names ... +struct XMarketParser +{ + // + string _version; // Temp ... + + // + bool IsIngot(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsErrante(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsAMarkets(string market) + { + // + bool result = false; + + // + result = IsValid(market) && + market == "AMarkets LLC"; + + // + return result; + } + + // + bool IsIFCMarkets(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsOtetMarkets(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // +}; + +// +struct XPoint +{ + // + // Props ... + double value; + datetime at; + + // + XPoint() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + value = 0; + at = NULL; + + // + ZeroMemory(this); + } + + // + bool IsValid() + { + // + return value > 0 && + IsValid(at); + } + + // +}; + +// +// Specified Swing Point ... +struct XSwingPoint +{ + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + + // + double swing; + datetime time; + ENUM_X_SWING_TYPE type; + + // + // Constructor ... + XSwingPoint() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + swing = 0; + time = NULL; + + // + symbol = NULL; + period = NULL; + + // + type = X_NO_SWING; + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + swing > 0 && + IsValid(time) && + IsValid(symbol) && + IsValid(period) && + type != X_NO_SWING; + + // + return result; + } + + /** + * Check Swing is Low or not ... + * + * @return ( bool ) + */ + bool IsSwingLow() + { + return type == X_SWING_LOW; + } + + /** + * Check Swing is High or not ... + * + * @return ( bool ) + */ + bool IsSwingHigh() + { + return type == X_SWING_HIGH; + } +}; + +/** + * Extract values of swings from specified Collection ... + * + * @param swings: XSwingPoint instance Collection ... + * @param values: double Collection ... + * + * @return ( int ) + */ +int ExtractSwings( + XSwingPoint &swings[], + double &values[] // +) +{ + // + int result = 0; + + // + Clean(values); + + // + int count = ArraySize(swings); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + Add( + swings[i].swing, + values // + ); + } + + // + result = ArraySize(values); + + // + return result; +} + +// +// Consolidation Zone ... +struct XConsolidationZone +{ + // + // Props ... + + // + string symbol; // Symbol ... + ENUM_TIMEFRAMES period; // Period ... + + // + double upper; // Upper ... + double lower; // Lower ... + + // + datetime from; // Start Date + datetime to; // Breake Date + + // + ENUM_X_DIRECTION dir; // Break Direction ... + + // + // Constructor ... + XConsolidationZone() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + upper = 0; + lower = 0; + + // + to = NULL; + from = NULL; + symbol = NULL; + period = NULL; + dir = X_DIRECTION_NONE; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + upper > 0 && + lower > 0 && + IsValid(to) && + IsValid(from) && + IsValid(symbol) && + IsValid(period) && + HasDirection(dir) + // + ; + + // + return result; + } + + bool IsSameAs( + XConsolidationZone &item // + ) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + dir == item.dir && + from == item.from && + upper == item.upper && + lower == item.lower && + symbol == item.symbol && + period == item.period; + + // + return result; + } + + /** + * Retrieve Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = + // + "XCZONE" + "_" + + ToString(dir) + "_" + + symbol + "_" + + ToString(period) + "_" + + ToString(upper) + "_" + + ToString(lower) + // + ; + + // + return result; + } + + // +}; + +// +// Functions ... + +// +// Validators ... + +// +// Validate an String has length and not NULL ... +bool IsValid(string value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + StringLen(value) > 0 + // + ; + + // + return result; +} +bool IsSpecifiedValid(string value) +{ + return IsValid(value); +} + +// +// Validate a Date ... +bool IsValid(datetime value) +{ + // + bool result = false; + + // + result = NotEmpty(value) && value != NULL; + + // + return result; +} +bool IsSpecifiedValid(datetime value) +{ + return IsValid(value); +} + +// +// Validate a Period Param ... +bool IsValid(ENUM_TIMEFRAMES value) +{ + // + bool result = false; + + // + result = + // + value != NULL + // + ; + + // + return result; +} +bool IsSpecifiedValid(ENUM_TIMEFRAMES value) +{ + // + return IsValid(value); +} + +// +// Validate Specified Cycle ... +bool IsValid(ENUM_X_MARKET_CYCLES value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MARKET_CYCLE_UNKNOWN + // + ; + + // + return result; +} + +// +// Validate Specific Period Mode ... +bool IsValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NOTHING + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} + +// +bool IsSpecifiedValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + return IsValid(mMethod, + mPeriod // + ); +} + +// +// Validate Swing Mode ... +bool IsValid(ENUM_X_SWING_TYPE value) +{ + // + bool result = false; + + // + result = + // + value == X_SWING_HIGH || + value == X_SWING_LOW + // + ; + + // + return result; +} + +// +// As IS ... + +// +// Determine a Position type is Long or not ... +bool IsLong(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_BUY; + + // + return result; +} +bool IsLong(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_BUY; + + // + return result; +} + +// +// Determine a Position type is Short or not ... +bool IsShort(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_SELL; + + // + return result; +} +bool IsShort(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_SELL; + + // + return result; +} + +// +// Retrieve Opposit Direction Type ... +ENUM_POSITION_TYPE GetOpposit(ENUM_POSITION_TYPE type) +{ + // + ENUM_POSITION_TYPE result = NULL; + + // + bool isLong = IsLong(type); + result = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + return result; +} +ENUM_ORDER_TYPE GetOpposit(ENUM_ORDER_TYPE type) +{ + // + ENUM_ORDER_TYPE result = NULL; + + // + bool isLong = IsLong(type); + result = isLong + ? ORDER_TYPE_SELL + : ORDER_TYPE_BUY; + + // + return result; +} + +// +string ToString(ENUM_POSITION_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} +string ToString(ENUM_ORDER_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} + +// +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); + + // + return result; +} + +// +// Find Chart ID ... +long FindChartID( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period +) +{ + // + long result = ChartFirst(); + long first = result; + + // + while (result > 0) + { + // + string chSymbol = ChartSymbol(result); + ENUM_TIMEFRAMES chPeriod = ChartPeriod(result); + + // + bool isOwn = + // + chSymbol == mSymbol && + chPeriod == mPeriod + // + ; + if (isOwn) + { + break; + } + + // + result = ChartNext(result); + } + + // + return result; +} + +// +// Normalizers ... + +// +// Check a Symbol provided or not ... +// if not use Default ... +string NormalizeSymbol(string value) +{ + // + string result = value; + + // + if (!IsValid(result)) + { + result = _Symbol; + } + + // + return result; +} + +// +// Check a Datetime provided or not ... +// if not use Current ... +datetime NormalizeTime(datetime value) +{ + // + datetime result = value; + + // + if (!IsValid(result)) + { + result = TimeCurrent(); + } + + // + return result; +} + +// +// Check a Period provided or not ... +// if not use Default ... +ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value) +{ + // + ENUM_TIMEFRAMES result = value; + + // + if (!IsValid(value)) + { + result = _Period; + } + + // + return result; +} + +// +// Normalize Cycle ... +ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value) +{ + // + ENUM_X_MARKET_CYCLES result = value; + + // + if (!IsValid(result)) + { + result = X_MARKET_CYCLE_SHORT; + } + + // + return value; +} + +// +// Validate a Buffer Size for Looping or etc ... +bool IsValidSize(int size) +{ + // + bool result = size > 0; + + // + return result; +} + +template +bool IsValidSize(T &buffer[]) +{ + // + bool result = false; + + // + result = + // + IsValidSize(ArraySize(buffer)) + // + ; + + // + return result; +} + +// +// Check a Given Index is Valid or not ... +bool IsValidIndex(int index) +{ + return index >= 0; +} + +// +// Normalize Index Based On Specified Buffer ... +template +void NormalizeIndex( + int &index, + T &buffer[] // +) +{ + // + int bufferSize = ArraySize(buffer); + + // + if (bufferSize <= 0) + { + index = 0; + } + + // + if (index <= 0) + { + index = 0; + } + + // + if (index > bufferSize - 1) + { + index = bufferSize - 1; + } +} + +// +// Normalize Start and Count based on Specified Buffer ... +template +void NormalizeCount( + int &start, + int &count, + T &buffer[] // +) +{ + // + // Validate Buffer Size ... + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return; + } + + // + // Normalization Start ... + NormalizeIndex( + start, + buffer // + ); + + // + if (count < start) + { + count = (start - count); + } + + // + // Normalization Count ... + + // + if (count < 0) + { + count = start; + } + + // + if (count > bufferSize) + { + count = bufferSize; + } +} + +// +// Normalize a give Volume ... +double NormalizeVolume( + double mVolume, // desired volume to normalize + string mSymbol = NULL, // Trading Symbol + int mLength = 2 // Length of Digits +) +{ + // + double result = mVolume; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + // Normalize Digits ... + int digits = GetDigits(mSymbol); + + // + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +// +// Normallize Price ... +double NormalizePrice( + double mPrice, // desired Price for normalization + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double tickSize = 0; + result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(mSymbol); + result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits); + + // + return result; +} + +// +// Prices ... + +// +// Retrieve Ask Price ... +double GetAsk( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_BID); + + // + return result; +} + +// +// Retrieve Spread Price ... +double GetSpread( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Retrieve Point Value ... +double GetPoints( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT); + + // + return result; +} + +// +// Retrieve Point Digits ... +int GetDigits( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Retrieve Entry Price ... +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Retrieve Exit Price ... +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double symbolPoint = GetPoints(mSymbol); + int symbolDigits = GetDigits(mSymbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + double mPips, // pips amount + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipValue = GetPipPrice(mSymbol); + double result = mPips * pipValue; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double mPrice, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPrice = NormalizePrice(mPrice, mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipPrice = GetPipPrice(mSymbol); + + // + double result = mPrice / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + price = NormalizePrice(price, mSymbol); + + // + double point = GetPoints(mSymbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points, // Points Amount + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double point = GetPoints(mSymbol); + result = points * point; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Series Mode to XPRICE ... +ENUM_X_PRICE ToPrice( + ENUM_SERIESMODE mMode // Specified Series Mode ... +) +{ + // + ENUM_X_PRICE result = X_PRICE_CLOSE; + + // + switch (mMode) + { + // + // High ... + case MODE_HIGH: + result = X_PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = X_PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = X_PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = X_PRICE_CLOSE; + break; + } + + // + return result; +} + +// +// Retrieve Applied Price ... +template +double GetAppliedPrice( + ENUM_APPLIED_PRICE tprice, // Type of Price Selection + T &open[], // Open Prices + T &high[], // High Preices + T &low[], // Low Prices + T &close[], // Close Prices + int i // Bar Index +) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} + +// +double iGetPrice( + int tprice, + double open, + double high, + const double low, + const double close // +) +{ + // + switch (tprice) + { + case PRICE_CLOSE: + return (close); + case PRICE_OPEN: + return (open); + case PRICE_HIGH: + return (high); + case PRICE_LOW: + return (low); + case PRICE_MEDIAN: + return ((high + low) / 2.0); + case PRICE_TYPICAL: + return ((high + low + close) / 3.0); + case PRICE_WEIGHTED: + return ((high + low + close + close) / 4.0); + } + + // + return (0); +} + +/** + * Calculates Price Change Percentage based on + * Several Params ... + * + * @param _symbol: Symbol ... + * @param _period: Time Frame ... + * @param _from: start Bar Index ... + * @param _length: Length of Bars ... + * + * @return ( double ) + */ +double GetPriceChanged( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _from = 0, + int _length = 3 // +) +{ + // + double result = 0; + + // + NormalizeSymbol(_symbol); + NormalizePeriod(_period); + + // + if (_from < 0) + { + _from = 0; + } + + // + if (_length < 2) + { + _length = 2; + } + + // + double closes[]; + int copiedCloses = CopyClose( + _symbol, + _period, + _from, + _length, + closes // + ); + if (copiedCloses < _length) + { + return result; + } + ArrayReverse(closes); + + // + double change = (closes[0] - closes[_length - 1]) / closes[_length - 1] * 100; + result = change; + + // + return result; +} + +// +// Calculate TP/SL for Specified Type of Positions ... +void CalculateTPSL( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mR2R = 1, // Provided Risk To Reward Ratio + double slPrice = 0, // Provided SL Price + double tpPrice = 0, // Provided TP Price + double priceToRisk = 0, // If Entry equal to Provided SL Price Risk Point + double priceToReward = 0 // If Entry equal to Provided TP Price Reward Point +) +{ + // + // if Both TP and SL Provided, ignore R2R and Calculate direct ... + // if SL provided, Calculate TP based on Provided R2R ... + // if TP provided, Calculate SL based on Provided R2R ... + // default R2R is set to 1 ... + + // + mSL = 0; + mTP = 0; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + (tpPrice <= 0 && slPrice <= 0)) + { + return; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = slPrice > 0 && + (isLong + ? slPrice <= mEntry + : slPrice >= mEntry); + + // + bool canCalculateBasedOnTP = tpPrice > 0 && + (isLong + ? tpPrice >= mEntry + : tpPrice <= mEntry); + + // + if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = MathAbs(mEntry - slPrice); + if (risk == 0) + { + risk = priceToRisk; + } + reward = risk * mR2R; + } + else if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = MathAbs(mEntry - tpPrice); + if (reward == 0) + { + reward = priceToReward; + } + risk = reward / mR2R; + } + else if (!canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + bool canSetTPPrice = isLong + ? tpPrice > mEntry + : tpPrice < mEntry; + if (canSetTPPrice) + { + mTP = tpPrice; + } + + // + bool canSetSLPrice = isLong + ? slPrice < mEntry + : slPrice > mEntry; + if (canSetSLPrice) + { + mSL = slPrice; + } + + // + return; + } + else if (canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + bool canSetTPPrice = isLong + ? tpPrice > mEntry + : tpPrice < mEntry; + if (canSetTPPrice) + { + mTP = tpPrice; + } + + // + bool canSetSLPrice = isLong + ? slPrice < mEntry + : slPrice > mEntry; + if (canSetSLPrice) + { + mSL = slPrice; + } + + // + return; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; +} + +// +bool CalculateTPSLByPoint( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mPointValue, // Point Value + double mR2R = 1, // Provided Risk To Reward Ratio + double slPoint = 0, // Provided SL Point + double tpPoint = 0 // Provided TP Point +) +{ + // + bool result = false; + + // + mSL = 0; + mTP = 0; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + mPointValue <= 0 || + (slPoint <= 0 && tpPoint <= 0)) + { + return result; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = slPoint > 0; + + // + bool canCalculateBasedOnTP = tpPoint > 0; + + // + if (!canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + return result; + } + + // + if (canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = tpPoint * mPointValue; + risk = slPoint * mPointValue; + } + else if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = tpPoint * mPointValue; + risk = reward / mR2R; + } + else if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = slPoint * mPointValue; + reward = risk * mR2R; + } + + // + result = risk > 0 && reward > 0; + if (!result) + { + return result; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + return result; +} + +// +bool CalculateTPSLByPrice( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mR2R = 1 // Provided Risk To Reward Ratio +) +{ + // + bool result = false; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + (mSL <= 0 && mTP <= 0)) + { + return result; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = mSL > 0; + bool canCalculateBasedOnTP = mTP > 0; + + // + if ( + !canCalculateBasedOnSL && + !canCalculateBasedOnTP) + { + return result; + } + + // + if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = MathAbs(mTP - mEntry); + risk = reward / mR2R; + } + else if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = MathAbs(mEntry - mSL); + reward = risk * mR2R; + } + + // + result = risk > 0 && reward > 0; + if (!result) + { + return result; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + return result; +} + +/** + * Retrieve Current Tick ... + */ +bool GetTick( + string mSymbol, + MqlTick &tick // +) +{ + return SymbolInfoTick(mSymbol, tick); +} + +/** + * Retrieve Tick Entry ... + */ +double GetTickEntry( + MqlTick &mTick, + ENUM_POSITION_TYPE type, + string mSymbol = NULL // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? mTick.ask + : mTick.bid; + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +/** + * Retrieve Tick Exit ... + */ +double GetTickExit( + MqlTick &mTick, + ENUM_POSITION_TYPE type, + string mSymbol = NULL // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? mTick.bid + : mTick.ask; + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +/** + * Calculate Momentum Changes based on Given Price + */ +double CalculateMomentum( + double currentPrice, + double previousPrice // +) +{ + // + double result = 0; + + // + return result; +} + +/** + * Detect Possible Momentum Changes + * Using MqlTick ... + */ +bool DetectMomentumChange( + ENUM_POSITION_TYPE type, + string mSymbol = NULL, + int mLength = 14 // +) +{ + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + MqlTick ticks[]; + int copied = CopyTicks( + mSymbol, + ticks, + COPY_TICKS_ALL, + 0, + mLength + 1 // + ); + + // + result = copied > mLength; + if (!result) + { + return result; + } + + // + double previousPrice = GetTickExit( + ticks[mLength], + type, + mSymbol // + ); + for (int i = mLength - 1; i >= 0; i--) + { + // + double currentPrice = GetTickExit( + ticks[i], + type, + mSymbol // + ); + + // + double momentum = CalculateMomentum( + currentPrice, + previousPrice // + ); + + // + if (fabs(momentum) > 1.0) + { + // + result = true; + break; + } + } + + // + return result; +} + +// +// Fill Specified Applied Prices ... +int FillPrice( + double &buffer[], + ENUM_APPLIED_PRICE _mAppliedTo = PRICE_CLOSE, + string _mSymbol = NULL, + ENUM_TIMEFRAMES _mPeriod = NULL, + int _mStart = 0, + int _mLoopback = 10 // +) +{ + // + int result = 0; + + // + if (_mStart < 0) + { + _mStart = 0; + } + + // + if (_mLoopback < 1) + { + _mLoopback = 1; + } + + // + _mSymbol = NormalizeSymbol(_mSymbol); + _mPeriod = NormalizePeriod(_mPeriod); + + // + Clean(buffer); + ArraySetAsSeries(buffer, true); + + // + double open[]; + result = CopyOpen( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + open // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double high[]; + result = CopyHigh( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + high // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double low[]; + result = CopyLow( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + low // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double close[]; + result = CopyClose( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + close // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + for (int i = 0; i < result; i++) + { + // + double iPrice = GetAppliedPrice( + _mAppliedTo, + open, + high, + low, + close, + i // + ); + + // + Add( + iPrice, + buffer // + ); + } + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Symbols ... + +// +// Retrieve Available Symbols ... +int GetAllSymbols( + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true // Force To Clean Result Array +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(symbols); + } + + // + int beforeSize = ArraySize(symbols); + + // + int symbolsCount = SymbolsTotal(onlyInWatchList); + if (symbolsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = SymbolName( + i, + onlyInWatchList + // + ); + if (!IsValid(iSymbol)) + { + continue; + } + + // + Add( + iSymbol, + symbols + // + ); + } + + // + int afterSize = ArraySize(symbols); + + // + result = afterSize - beforeSize; + + // + return result; +} + +// +// This is a Global Way to Filter Symbols +// you can pass Specific string as Query or a List String for Filtering ... +int FilterSymbols( + string query, // Which Query to Search Symbol + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true, // Force To Clean Result Array + bool ignoreCase = true, // Ignore Case + string querySeparator = "," // If Provided means query is a COllection of Queries and need to be Splitted +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(symbols); + } + + // + if (!IsValid(query)) + { + return result; + } + + // + // Check Query is an String array or not ... + string mQueries[]; + int queriesCount = 0; + if (IsValid(querySeparator) && Contains(querySeparator, query, true)) + { + // + queriesCount = SplitContent( + mQueries, + query, + querySeparator + // + ); + } + + // + int beforeSize = ArraySize(symbols); + + // + string allSymbols[]; + int allSymbolsCount = GetAllSymbols( + allSymbols, + onlyInWatchList, + forceClean); + if (allSymbolsCount <= 0) + { + return result; + } + + // + // Loop Through all Symbols ... + for (int i = 0; i < allSymbolsCount; i++) + { + // + string iSymbol = allSymbols[i]; + + // + bool isFilterPassed = false; + if (queriesCount == 0) + { + // + isFilterPassed = Contains( + query, + iSymbol, + ignoreCase + // + ); + } + else if (queriesCount > 0) + { + // + isFilterPassed = Contains( + mQueries, + iSymbol, + ignoreCase + // + ); + } + + // + if (isFilterPassed) + { + // + Add( + iSymbol, + symbols + // + ); + } + } + + // + int afterSize = ArraySize(symbols); + + // + result = afterSize - beforeSize; + + // + return result; +} + +// +int FilterUSDSymbols( + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true, // Force To Clean Result Array + bool ignoreCase = true, // Ignore Case + string querySeparator = "," // If Provided means query is a COllection of Queries and need to be Splitted +) +{ + // + return FilterSymbols( + "USD", + symbols, + onlyInWatchList, + forceClean, + ignoreCase, + querySeparator + // + ); +} + +// +// Time / Date ... + +// +// 0 => Sunday +// 1 => Monday +// 2 => Tuesday +// 3 => Wednesday +// 4 => Thursday +// 5 => Friday +// 6 => Saturday +enum ENUM_X_WEEK_DAYS +{ + X_WEEK_DAY_NONE = -1, + X_WEEK_DAY_SUNDAY = 0, + X_WEEK_DAY_MONDAY = 1, + X_WEEK_DAY_TUESDAY = 2, + X_WEEK_DAY_WEDNESDAY = 3, + X_WEEK_DAY_THURSDAY = 4, + X_WEEK_DAY_FRIDAY = 5, + X_WEEK_DAY_SATURDAY = 6, +}; + +// +// Retrieve Day of Week ... +ENUM_X_WEEK_DAYS GetDayOfWeek( + datetime time = NULL // +) +{ + // + ENUM_X_WEEK_DAYS result = X_WEEK_DAY_NONE; + + // + time = NormalizeTime(time); + MqlDateTime timeStruct; + bool hasDate = TimeToStruct( + time, + timeStruct // + ); + if (!hasDate) + { + return result; + } + + // + result = (ENUM_X_WEEK_DAYS)timeStruct.day_of_week; + + // + return result; +} + +// +// Representation of Time Struct ... +// struct MqlDateTime +// { +// int year; // Year +// int mon; // Month +// int day; // Day +// int hour; // Hour +// int min; // Minutes +// int sec; // Seconds +// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) +// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero) +// }; + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Hours to Seconds ... +int HoursToSeconds(int value) +{ + // + int result = 0; + + // + if (value < 0) + { + value = 0; + } + + // + if (value == 0) + { + return result; + } + + // + result = value * 60 * 60; + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + datetime cTime = TimeCurrent(); + TimeToStruct(cTime, result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +int GetLocalOffset() +{ + // + MqlDateTime cTimeStruct; + datetime cTime = TimeCurrent(cTimeStruct); + + // + MqlDateTime cLTimeStruct; + datetime cLTime = TimeLocal(cLTimeStruct); + + // + cTimeStruct.sec = 0; + cTime = StructToTime(cTimeStruct); + + // + cLTimeStruct.sec = 0; + cLTime = StructToTime(cLTimeStruct); + + // + int result = ((int)cLTime - (int)cTime); + + // + return result; +} + +// +int GetUTCRequiredTimeOffset() +{ + // + int utcOffset = TimeGMTOffset(); + int localOffset = GetLocalOffset(); + + // + int result = utcOffset + localOffset; + + // + return result; +} + +// +datetime GetUTCTime( + datetime time = NULL, + bool applyTradeServerTime = false // +) +{ + // + datetime result = NULL; + + // + NormalizeTime(time); + + // + datetime cTime = TimeCurrent(); + datetime cTimeLocal = TimeLocal(); + + // + int cLocalOffset = ((int)cTimeLocal - (int)cTime); + int gmtOffset = TimeGMTOffset(); + int offsetDelte = gmtOffset + cLocalOffset; + int requiredUTCOffset = GetUTCRequiredTimeOffset(); + if (requiredUTCOffset > 0) + { + requiredUTCOffset = -1 * requiredUTCOffset; + } + + // + int timeSeconds = (int)time; + int resultSeconds = timeSeconds + requiredUTCOffset; + + // + result = (datetime)(resultSeconds); + + // + return result; +} + +// +// Retrieve only Hour and Minute as String ... +string GetTimeString( + datetime time = NULL // +) +{ + // + NormalizeTime(time); + + // + string result = NULL; + + // + MqlDateTime tStruct; + bool isStructed = TimeToStruct(time, tStruct); + if (!isStructed) + { + return result; + } + + // + string hour = ToString(tStruct.hour); + hour = + StringLen(hour) == 1 + ? "0" + hour + : hour; + + // + string minute = ToString(tStruct.min); + minute = + StringLen(minute) == 1 + ? "0" + minute + : minute; + + // + result = hour + ":" + minute; + + // + return result; +} + +// +// Converts a Date time to File Format ... +string ToFormatString( + datetime mTime, + string separator = "_" // +) +{ + // + string result = NULL; + + // + if (!IsValid(mTime)) + { + return result; + } + + // + MqlDateTime timeStruct; + bool isConverts = TimeToStruct( + mTime, + timeStruct // + ); + if (!isConverts) + { + return result; + } + + // + string year = ToString(timeStruct.year); + string month = ToString(timeStruct.mon); + string day = ToString(timeStruct.day); + string hour = ToString(timeStruct.hour); + string minute = ToString(timeStruct.min); + string second = ToString(timeStruct.sec); + + // + result = + // + // Year ... + year + separator + + // + // Month ... + (StringLen(month) == 1 + ? "0" + month + : month) + + separator + + // + // Day ... + (StringLen(day) == 1 + ? "0" + day + : day) + + separator + + // + // Hour ... + (StringLen(hour) == 1 + ? "0" + hour + : hour) + + separator + + // + // Minute ... + (StringLen(minute) == 1 + ? "0" + minute + : minute) + + separator + + // + // Seconds ... + (StringLen(second) == 1 + ? "0" + second + : second) + + separator + + // + "" + // + ; + + // + return result; +} + +/** + * Converts an String Represetation of Time (00:00) to Date Time .. + * + * @param value: String ... + * + * @return ( datetime ) + */ +datetime ParseDateTimeFromTimeString(string value) +{ + // + datetime result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + // Check Signalling Time ... + MqlDateTime cTime; + bool isTimeRecieved = TimeCurrent(cTime); + if (!isTimeRecieved) + { + return result; + } + + // + // Split ... + string parts[]; + int partsCount = SplitContent( + parts, + value, + ":" + // + ); + if (!IsValidSize(partsCount)) + { + return result; + } + + // + int hour = 0; + int minute = 0; + if (partsCount >= 1) + { + hour = (int)(parts[0]); + } + if (partsCount >= 2) + { + minute = (int)(parts[1]); + } + + // + cTime.day_of_week = 0; + cTime.day_of_year = 0; + + // + cTime.hour = hour; + cTime.min = minute; + + // + result = StructToTime(cTime); + + // + return result; +} + +// +// Check Specific Time in Range of another Time ... +bool IsTimeInRange( + datetime currentTime = NULL, + datetime startTime = NULL, + datetime stopTime = NULL // +) +{ + // + bool result = false; + + // + // Normallize Current Time ... + currentTime = NormalizeTime(currentTime); + + // + result = !IsValid(startTime) && + !IsValid(stopTime); + if (result) + { + return result; + } + + // + result = IsValid(startTime) && + IsValid(stopTime); + if (!result) + { + // + result = IsValid(startTime) && + currentTime >= startTime; + + // + return result; + } + + // + result = currentTime >= startTime && + currentTime < stopTime; + + // + return result; +} +bool IsTimeInRange( + datetime currentTime, + string startTime, + string endTime // +) +{ + // + bool result = false; + + // + result = IsValid(startTime) && + IsValid(endTime); + if (!result) + { + // + // Here Since there isnot provide any + // data source we pass result as true ... + result = true; + return result; + } + + // + // Converts String Representation to Time ... + datetime st = ParseDateTimeFromTimeString(startTime); + datetime et = ParseDateTimeFromTimeString(endTime); + + // + result = IsTimeInRange( + currentTime, + st, + et // + ); + + // + return result; +} + +// +// Bar Times ... + +// +// Retrieve Specified Bar Time ... +datetime GetBarTime( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + // Retrieve Bar Time ... + datetime result = iTime( + mSymbol, + mPeriod, + barIndex); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsMilliSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Bar Time Structure ... +MqlDateTime GetBarTimeStruct( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Retrieve Last Available Bar Time of +// Dest Period inside Source Period ... +datetime GetLastBarTime( + ENUM_TIMEFRAMES sourcePeriod, + ENUM_TIMEFRAMES destPeriod // +) +{ + // + datetime result = NULL; + + // + if (!IsValid(sourcePeriod) || + !IsValid(destPeriod)) + { + return result; + } + + // + int sourceSeconds = PeriodSeconds(sourcePeriod); + int destSeconds = PeriodSeconds(destPeriod); + if (sourceSeconds < destSeconds) + { + return result; + } + + // + XOHCL sourceBar; + bool isInited = sourceBar.Init( + _Symbol, + sourcePeriod, + 0 // + ); + if (!isInited) + { + return result; + } + + // + result = (datetime)((((int)sourceBar.time) + sourceSeconds) - destSeconds); + + // + return result; +} + +// +// Other Tools ... + +// +template +bool IsSame( + T &buffer[], // Search Buffer + int count = 5, // Number of Searchs + int start = 0 // Start ... +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + result = bufferSize > 0; + if (!result) + { + return result; + } + + // + // Validate Count ... + result = start + count < bufferSize; + if (!result) + { + return result; + } + + // + T iTem = buffer[start]; + for (int i = start; i < start + count; i++) + { + // + if (iTem != buffer[i]) + { + result = false; + break; + } + + // + if (!result) + { + result = true; + } + } + + // + return result; +} + +// +// Check first Cross Over second at index ... +bool IsCrossedOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + !(first[index + 1] > second[index + 1]); + + // + return result; +} + +// +// Check first is Over second at index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + first[index + 1] > second[index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at index ... +bool IsCrossedUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + !(first[index + 1] < second[index + 1]); + + // + return result; +} + +// +// Check first is Under second at index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + first[index + 1] < second[index + 1]; + + // + return result; +} + +// +// Check if a Value Increasing in Loopback ... +bool IsIncreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue >= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue >= iValue; + + // + bool isIIncreasing = IsIncreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIIncreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Check if a Value Decreasing in Loopback ... +bool IsDecreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue <= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue <= iValue; + + // + bool isIDecreasing = IsDecreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIDecreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +bool IsTrendingUp( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = upCounts > 1 && upCounts > downCounts; + + // + return result; +} + +// +bool IsTrendingDown( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = downCounts > 1 && downCounts > upCounts; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + const double &buffer[], // Buffer + int from, // In Past Index ... + int to // In Past Index ... +) +{ + // + double result = 0; + + // + if (from > ArraySize(buffer) || to > ArraySize(buffer)) + { + return result; + } + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Check Bar Reject Specified Value ... +bool IsBarReject( + double value, + ENUM_X_DIRECTION dir, + XOHCL &bar // +) +{ + // + bool result = false; + + // + result = value > 0 && + bar.IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + bool isUp = IsBullish(dir); + bool isDown = IsBearish(dir); + + // + result = + // + isUp + ? bar.IsBullish() && + bar.low < value && + bar.GetDown() > value + : isDown + ? bar.IsBearish() && + bar.high > value && + bar.GetUp() < value + : false + // + ; + + // + return result; +} + +// +// Check Bar Break Specified Value ... +bool IsBarBreak( + double value, + ENUM_X_DIRECTION dir, + XOHCL &bar // +) +{ + // + bool result = false; + + // + result = value > 0 && + bar.IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + bool isUp = IsBullish(dir); + bool isDown = IsBearish(dir); + + // + result = + isUp + ? bar.IsBullish() && + ((bar.GetDown() < value && + bar.GetUp() > value) || + (bar.close > value && + pBar.close < value)) + : isDown + ? bar.IsBearish() && + ((bar.GetUp() > value && + bar.GetDown() < value) || + (bar.close < value && + pBar.close > value)) + : false; + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, // Upper Bound + double downPrice, // Downer Bound + double level, // Level Multiplier Factor + int direction // From Down to Up < 0, other wise Vice Versa + // +) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + + // + return result; +} + +// +double GetFibonacciLevel( + double mUp, + double mDown, + ENUM_X_FIBO_LEVELS mLevel, + ENUM_X_DIRECTION mForDir // +) +{ + // + double result = 0; + + // + double levelValue = GetFiboLevelValue(mLevel); + + // + bool isValid = + // + mUp > 0 && + mDown > 0 && + levelValue > 0 && + mUp > mDown && + HasDirection(mForDir) + // + ; + if (!isValid) + { + return result; + } + + // + bool isBullish = IsBullish(mForDir); + + // + double ling = mUp - mDown; + double pLevel = (ling / 100) * (levelValue * 100); + + // + result = + isBullish + ? mUp - pLevel + : mDown + pLevel; + + // + return result; +} + +// +// Method 1 +// Normalize between 1 and 0 ... +template +double GetNormalizedValueMethod1( + T &buffer[], // Array which required to Normalize + int mLength, // Length of Normalization + int mStart = 0, // start index + int digits = 5 // Normalization Digits +) +{ + // + double result = 0; + + // + if (digits <= 5) + { + digits = 5; + } + + // + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return result; + } + + // + // Normalize Count ... + NormalizeCount( + mStart, + mLength, + buffer // + ); + + // + T max = 0; + T min = 0; + + // + if (bufferSize != mLength) + { + // + T tmp[]; + Copy( + mStart, + mLength, + buffer, + tmp // + ); + + // + max = GetMax(tmp); + min = GetMin(tmp); + } + + // + if (bufferSize == mLength) + { + // + max = GetMax(buffer); + min = GetMin(buffer); + } + + // + T iValue = buffer[mStart]; + + // + double minMaxDiff = (max - min); + if (minMaxDiff <= 0) + { + return result; + } + + // + result = (iValue - min) / minMaxDiff; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Method 2 +// Normalize Between Specified Upper and Lower ... +template +double GetNormalizedValueMethod2( + T &buffer[], // Array which required to Normalize + int mLength, // Length of Normalization + int mUpper, // Specified Upper Value + int mLower, // Specified Lower Value + int mStart = 0, // start index + int digits = 5 // Normalization Digits +) +{ + // + double result = 0; + + // + if (digits <= 5) + { + digits = 5; + } + + // + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return result; + } + + // + // Normalize Count ... + NormalizeCount( + mStart, + mLength, + buffer // + ); + + // + T max = 0; + T min = 0; + + // + if (bufferSize != mLength) + { + // + T tmp[]; + Copy( + mStart, + mLength, + buffer, + tmp // + ); + + // + max = GetMax(tmp); + min = GetMin(tmp); + } + + // + if (bufferSize == mLength) + { + // + max = GetMax(buffer); + min = GetMin(buffer); + } + + // + T iValue = buffer[mStart]; + + // + double minMaxDiff = (max - min); + double boundaryDiff = (mUpper - mLower); + if (minMaxDiff <= 0 || boundaryDiff <= 0) + { + return result; + } + + // + result = boundaryDiff / (minMaxDiff * (iValue - max) + max); + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +void NormalizeBuffer( + double &source[], // Source Buffer + double &dest[], // Result Buffer + double upper = 100, // Upper Value to Normalize + double lower = -100, // Lower Value to Normalize + int size = -1, // Size Of Normalization + int digits = 5 // Digits for Result +) +{ + // + if (size <= 0) + { + size = ArraySize(source); + } + + // + bool asSeriesFlag = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(source, false); + ArraySetAsSeries(dest, false); + + // + double min = ArrayMinimum(source, 0, size); + double max = ArrayMaximum(source, 0, size); + + // + for (int i = 0; i < size; i++) + { + // + double iNormal = lower + ((source[i] - min) / (max - min)) * (upper - lower); + + // + if (digits > 0) + { + iNormal = NormalizeDouble(iNormal, digits); + } + + // + dest[i] = iNormal; + } + + // + ArraySetAsSeries(source, asSeriesFlag); + ArraySetAsSeries(dest, asSeriesFlag); +} + +// +// Templates ... + +// +// Retrieve Specific Object Types Name ... +template +string GetTypeName(const T &t) +{ + return typename(T); +} + +// +template +string GetToken(T &item) +{ + // + string mType = GetTypeName(item); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; +} + +// +// Same as Get Token for Use in Classes ... +template +string GetSpecificToken(T &item) +{ + // + string mType = GetTypeName(item); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; +} + +// +// Generate Unique Tags ... +template +string GenerateTag(T &model) +{ + // + string result = ""; + + // + string tag = model.ToString(); + if (StringLen(tag) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(tag); + + // + return result; +} + +// +// Hash Specified Content ... +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToString(content); + if (StringLen(strContent) == 0) + { + return result; + } + + // + static XCMD5 md5; + + // + result = md5.Hash(strContent); + + // + return result; +} + +// +// Check a Value Not Empty ... +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Check a Value Not Empty and Zero ... +template +bool NotEmptyZero(T value) +{ + return value != EMPTY_VALUE && value != 0; +} + +// +// Add Specified Item to Array ... +template +int Add( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} +template +int AddSpecific( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + return Add( + item, + buffer // + ); +} +template +int AddRef( + T &item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Check Specified Array Has Childs or not ... +template +bool HasChild(T &buffer[]) +{ + return IsValidSize(ArraySize(buffer)); +} +template +bool SpecificHasChild(T &buffer[]) +{ + return HasChild(buffer); +} + +// +// Remove Specified Item from an Array ... +template +bool Remove( + T item, + T &buffer[]) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) + { + return result; + } + + // + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Clean Specified Array ... +template +void Clean(T &buffer[]) +{ + // + ArrayResize(buffer, 0); + ArrayFree(buffer); + ZeroMemory(buffer); +} +template +void SpecificClean(T &buffer[]) +{ + Clean(buffer); +} + +// +// Copy Whole Content of Source to Dest array ... +template +void Copy( + T &source[], // Source Buffer ... + T &dest[], // Dest Buffer ... + bool cleanDest = true // Force Clen Dest Buffer ... +) +{ + // + if (cleanDest) + { + Clean(dest); + } + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + AddRef( + iSource, + dest); + } +} + +// +// Copy Items from a Buffer ... +template +int Copy( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true, // Force To Clean buffer + bool forceStart = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0 && forceStart) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + if (count == 0) + { + count = ArraySize(source) - 1 - start; + } + + // + if (start + count > ArraySize(source)) + { + return result; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + ArrayCopy( + dest, + source, + 0, + start, + count + // + ); + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Copy Items from a Buffer ... +template +int CopyRef( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + for (int i = start; i < start + count; i++) + { + // + AddRef( + source[i], + dest + // + ); + } + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Retrive Last Item of Specified Buffer ... +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +// Remove Last Item of Specified Buffer ... +template +bool RemoveLastItem( + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int count = ArraySize(buffer); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + ArrayRemove( + buffer, + count - 1, + 1 // + ); + + // + return result; +} + +template +void CleanupArray( + T &buffer[], // Buffer to Cleanup ... + int maxAllowed = 0 // Max Allowed Number of items ... +) +{ + // + if (maxAllowed <= 0) + { + return; + } + + // + int count = ArraySize(buffer); + if (!IsValidSize(count) || + count <= maxAllowed) + { + return; + } + + // + int mustRemove = count - maxAllowed; + if (!IsValidSize(mustRemove)) + { + return; + } + + // + ArrayRemove( + buffer, + 0, + mustRemove // + ); +} + +template +void CleanupArray( + int &removedIndexes[], + T &buffer[] // Buffer to Cleanup ... +) +{ + // + bool isValid = HasChild(buffer) && + HasChild(removedIndexes); + if (!isValid) + { + return; + } + + // + for (int i = 0; i < ArraySize(removedIndexes); i++) + { + // + int idx = removedIndexes[i]; + if (IsValidIndex(idx) && ArraySize(buffer) > idx) + { + // + ArrayRemove( + buffer, + idx, + 1 // + ); + } + } + + // + Clean(removedIndexes); +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } + } + + // + return result; +} +// +// Find Specific Item Index inside a Collection ... +template +int FindIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + // + int result = -1; + + // + // Check Item Validation ... + if (!item.IsValid()) + { + return result; + } + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + // Validate Item ... + if (!iItem.IsValid()) + { + continue; + } + + // + bool isSame = item.IsSameAs(iItem); + if (isSame && result <= -1) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// Check an Array Contains Specified Value ... +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + bool result = false; + + // + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +// Calculate a Buffer's Sum ... +template +double GetSum( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / tmpCount; + + // + return result; +} + +// +// Get Max of Specific Loopback of a Buffer ... +template +T GetMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetMax( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + index = -1; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + bool isNew = result == 0; + bool canSet = isNew || + (!isNew && + result < iValue); + if (canSet) + { + // + index = i; + result = iValue; + } + } + + // + return result; +} +template +T GetSpecifiedMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMax( + buffer, + start, + count // + ); +} +template +T GetSpecifiedMax( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMax( + buffer, + index, + start, + count // + ); +} + +// +// Get Min of Specific Loopback of a Buffer ... +template +T GetMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetMin( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + index = -1; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + bool isNew = result == 0; + bool canSet = isNew || + (!isNew && + result > iValue); + if (canSet) + { + // + index = i; + result = iValue; + } + } + + // + return result; +} +template +T GetSpecifiedMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMin( + buffer, + start, + count // + ); +} +template +T GetSpecifiedMin( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMin( + buffer, + index, + start, + count // + ); +} + +// +// Find a Value less than Specified ... +template +T FindLesserThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} +template +T FindLesserThan( + T value, // Specified Value ... + int &index, // Item Index ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + index = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + index = i; + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindBiggerThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} +template +T FindBiggerThan( + T value, // Specified Value ... + int &index, // Item Index ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + index = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + index = i; + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find Same Values in Array ... +template +void FindSames( + T &result[], // Holds Result ... + T &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + T mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + T iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3 // +) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Bar XOHCL ... + +// +// Extract Specific Range of Bars ... +// using Start Bar Index ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int total = Bars( + mSymbol, + mPeriod); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + mSymbol, + mPeriod, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; +} + +// +// Extract Specific Range of Bars ... +// using Start Bar Time ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + from, + false + // + ); + + // + return GetBars( + result, + mSymbol, + mPeriod, + barIndex, + count, + forceClean + // + ); +} + +// +// String ... + +// +// Search a Content Contains Specific String or not ... +bool Contains( + string mQuery, // Search String + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + // + bool result = false; + + // + // Validate Query ... + result = IsValid(mQuery); + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + // Normalize Inputs ... + string query = mQuery; + string content = mContent; + if (ignoreCase) + { + // + StringToLower(query); + StringToLower(content); + } + + // + int queryIdx = StringFind( + content, + query); + + // + result = queryIdx >= 0; + + // + return result; +} + +// +bool Contains( + string &mQueries[], // Search Strings + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + // + bool result = false; + + // + // Validate Queries ... + int queriesCount = ArraySize(mQueries); + result = queriesCount > 0; + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + int containsCount = 0; + for (int i = 0; i < queriesCount; i++) + { + // + bool isContains = Contains( + mQueries[i], + mContent, + ignoreCase); + + // + if (!isContains) + { + // + result = false; + break; + } + + // + containsCount++; + } + + // + result = containsCount == queriesCount; + + // + return result; +} + +// +int FindIndexes( + string mQuery, // Search String + string mContent, // Search Content + int &result[], // Holding Results + bool ignoreCase = false // Ignore Case +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Inputs ... + if (!IsValid(mQuery) || + !IsValid(mContent)) + { + return mResult; + } + + // + // Apply Ignore Case if Provided ... + if (ignoreCase) + { + // + bool isConverted = StringToLower(mQuery); + if (!isConverted) + { + return mResult; + } + + // + isConverted = StringToLower(mContent); + if (!isConverted) + { + return mResult; + } + } + + // + // Search First Index ... + int lastPos = 0; + int idx = StringFind( + mContent, + mQuery, + lastPos // + ); + while (idx >= 0) + { + // + // Add Position to Result ... + Add( + idx, + result // + ); + + // + lastPos = idx + StringLen(mQuery); + idx = StringFind( + mContent, + mQuery, + lastPos // + ); + } + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Convert From String ... +template +T FromString(string value) +{ + // + T result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + result = (T)value; + + // + return result; +} + +// +// Converts an item to String ... +template +string ToString(T value) +{ + return (string)value; +} + +// +// Used In Report or Summary Generators ... +string ToString( + string prefix, // Title + bool value, // Value + bool ignoreFalseConditions = true, // Ignore False Conditions + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + result = (value || !ignoreFalseConditions) + ? prefix + + prefixSeparator + " " + + ToString(value) + + lineSeparator + : ""; + + // + return result; +} + +// +template +string ToString( + string prefix, // Title + T value, // Value + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + result = prefix + + prefixSeparator + " " + + ToString(value) + + lineSeparator; + + // + return result; +} + +// +string SetLabel( + string mLabel, // Provided Label ... + string value, // Source Value ... + string separator = "\n", // Line Separator + bool addTopEmptyLine = true // Add Empty Line On top +) +{ + // + string result = value; + + // + if (StringLen(mLabel) <= 0) + { + return result; + } + + // + result = (StringLen(value) > 0) + ? (addTopEmptyLine ? separator : "") + + mLabel + + separator + + "-----------------------------" + + separator + + value + : value; + + // + return result; +} + +// +// Converts a Buffer to String Representation ... +template +string ToString( + const T &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} + +// +// Converts String to boolean ... +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (StringLen(value) <= 0) + { + return result; + } + + // + StringToLower(value); + result = value == "true"; + + // + return result; +} + +// +// Split an String Representation of an Array ... +int SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + int mResult = 0; + + // + if (forceCleanResult) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return mResult; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +string ExtractSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + return ExtractString( + surrounded, + mToken + startString, + endString + // + ); +} + +// +int ParseIntSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (int)strContent; + + // + return result; +} +long ParseLongSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + long result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (long)strContent; + + // + return result; +} +string ParseStringSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (string)strContent; + + // + return result; +} +double ParseDoubleSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + double result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (double)strContent; + + // + return result; +} +datetime ParseTimeSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + datetime result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (datetime)strContent; + + // + return result; +} + +// +int ParseIntArraySurrounded( + int &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + int iValue = (int)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseLongArraySurrounded( + long &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + long iValue = (long)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseDoubleArraySurrounded( + double &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + double iValue = (double)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseTimeArraySurrounded( + datetime &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + datetime iValue = (datetime)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +// +// Surround an String by Specific Token ... +template +string Surround( + string mToken, // an String which used to Tokenize + T &value, // a Value for Tokenize it + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string strValue = ToString(value); + if (!IsValid(strValue)) + { + return result; + } + + // + result = + // + (IsValid(mToken) + ? mToken + : "") + + // + startString + + strValue + + endString + // + ; + + // + return result; +} + +// +template +string SurroundArray( + string mToken, + T &value[], + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string valueStr = ToString(value); + if (!IsValid(valueStr)) + { + return result; + } + + // + result = Surround( + mToken, + valueStr, + startString, + endString + // + ); + + // + return result; +} + +// +// Periods / Cycles ... + +// +// Converts an String to TimeFrame ... +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +// +// Converts Period to String ... +string ToString(ENUM_TIMEFRAMES mPeriod) +{ + // + string result = ""; + + // + string mPStr = EnumToString(mPeriod); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// Retrieve All Available Period as an Array ...s +int GetAllAvailablePeriods( + ENUM_TIMEFRAMES &result[] // Holds Result ... +) +{ + // + Clean(result); + + // + Add( + PERIOD_M1, + result + // + ); + + // + Add( + PERIOD_M2, + result + // + ); + + // + Add( + PERIOD_M3, + result + // + ); + + // + Add( + PERIOD_M4, + result + // + ); + + // + Add( + PERIOD_M5, + result + // + ); + + // + Add( + PERIOD_M6, + result + // + ); + + // + Add( + PERIOD_M10, + result + // + ); + + // + Add( + PERIOD_M12, + result + // + ); + + // + Add( + PERIOD_M15, + result + // + ); + + // + Add( + PERIOD_M20, + result + // + ); + + // + Add( + PERIOD_M30, + result + // + ); + + // + Add( + PERIOD_H1, + result + // + ); + + // + Add( + PERIOD_H2, + result + // + ); + + // + Add( + PERIOD_H3, + result + // + ); + + // + Add( + PERIOD_H4, + result + // + ); + + // + Add( + PERIOD_H6, + result + // + ); + + // + Add( + PERIOD_H8, + result + // + ); + + // + Add( + PERIOD_H12, + result + // + ); + + // + Add( + PERIOD_D1, + result + // + ); + + // + Add( + PERIOD_W1, + result + // + ); + + // + Add( + PERIOD_MN1, + result + // + ); + + // + int mResult = ArraySize(result); + + // + return mResult; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time of Host Period ... +) +{ + // + // Normalize Arg ... + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false + // + ); + + // + datetime result = GetBarTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; +} + +// +// Converts an String to it's related Market Cycle ... +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} + +// +// Converts a Cycle to it's String Representation ... +string ToString(ENUM_X_MARKET_CYCLES cycle) +{ + // + string result = ""; + + // + string mPStr = EnumToString(cycle); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[3]; + + // + return result; +} + +// +// Retrieve all Available Cycles ... +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[]) +{ + // + int mResult = 0; + + // + Clean(result); + + // + ENUM_X_MARKET_CYCLES tmp[] = { + X_MARKET_CYCLE_UNKNOWN, + X_MARKET_CYCLE_SHORT, + X_MARKET_CYCLE_MEDIUM, + X_MARKET_CYCLE_LONG, + X_MARKET_CYCLE_HIND}; + + // + Copy( + tmp, + result // + ); + + // + Clean(tmp); + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Retrieve Nearest Period base on Given Period ... +ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M5; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M10; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M20; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H3; + break; + + // + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + result = PERIOD_H6; + break; + + // + case PERIOD_H6: + result = PERIOD_H8; + break; + + // + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Mediest Period base on Given Period ... +ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M10; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M15; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M30; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H4; + break; + + // + case PERIOD_H3: + result = PERIOD_H6; + break; + + // + case PERIOD_H4: + result = PERIOD_H8; + break; + + // + case PERIOD_H6: + result = PERIOD_H12; + break; + + // + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Longest Period base on Given Period ... +ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M30; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H1; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H2; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H6; + break; + + // + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H4: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + result = PERIOD_D1; + break; + + // + case PERIOD_H8: + result = PERIOD_W1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Hindmost Period base on Given Period ... +ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_H1; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H2; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H4; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H6; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H8; + break; + + // + case PERIOD_H3: + result = PERIOD_H12; + break; + + // + case PERIOD_H4: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + result = PERIOD_W1; + break; + + // + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Specified Cycles Period related to Host Period ... +ENUM_TIMEFRAMES GetCyclePeriod( + ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle + ENUM_TIMEFRAMES mPeriod = NULL // Host Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + mPeriod = NormalizePeriod(mPeriod); + mCycle = NormalizeCycle(mCycle); + + // + switch (mCycle) + { + // + // Short ... + case X_MARKET_CYCLE_SHORT: + result = GetNearestPeriod(mPeriod); + break; + + // + // Medium ... + case X_MARKET_CYCLE_MEDIUM: + result = GetMediestPeriod(mPeriod); + break; + + // + // Long ... + case X_MARKET_CYCLE_LONG: + result = GetLongestPeriod(mPeriod); + break; + + // + // Hind ... + case X_MARKET_CYCLE_HIND: + result = GetHindMostPeriod(mPeriod); + break; + } + + // + return result; +} + +// +// Calculate a Cycle Length based on Host Period ... +int GetCycleLengthOn( + ENUM_TIMEFRAMES _hostPeriod, + ENUM_X_MARKET_CYCLES _cycle, + ENUM_X_PERIOD_METHOD _method, + ENUM_TIMEFRAMES _period // +) +{ + // + int result = 0; + + // + // Validate ... + bool isValid = + // + IsValid(_hostPeriod) && + IsValid(_method, _Period) + // + ; + if (!isValid) + { + return result; + } + + // + // Calculate Period ... + isValid = + _method != X_PERIOD_NOTHING && + _cycle != X_MARKET_CYCLE_UNKNOWN; + if (!isValid) + { + return result; + } + + // + if (_method == X_PERIOD_AUTO) + { + // + _period = GetCyclePeriod( + _cycle, + _hostPeriod // + ); + } + isValid = IsValid(_period); + if (!isValid) + { + return result; + } + + // + int _hostPeriodSeconds = PeriodSeconds(_hostPeriod); + int _periodSeconds = PeriodSeconds(_period); + + // + isValid = _periodSeconds >= _hostPeriodSeconds; + if (!isValid) + { + return result; + } + + // + result = _periodSeconds / _hostPeriodSeconds; + + // + return result; +} + +// +// Direction ... + +// +bool HasDirection(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value != X_DIRECTION_NONE && + value != X_DIRECTION_ALL; + + // + return result; +} + +// +bool IsBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} +bool IsSpecifiedBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} + +// +bool IsBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} +bool IsSpecifiedBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} + +// +ENUM_X_DIRECTION Opposit(ENUM_X_DIRECTION value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + if (!HasDirection(value)) + { + return result; + } + + // + result = + IsBullish(value) + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + + // + return result; +} + +// +// Moving Average ... + +enum ENUM_X_MA_METHOD +{ + X_MA_MODE_NONE, // None + X_MA_MODE_SMA, // SMA + X_MA_MODE_EMA, // EMA + X_MA_MODE_LWMA, // LWMA + X_MA_MODE_SMMA, // SMMA +}; + +/** + * Calculate Sspecified Buffer's Moving Averages ... + * + * @param rates_total: Integer, number of items ... + * @param prev_calculated: Integer, Previous Calculate Items ... + * @param begin: Integer, Bar Index ... + * @param period: Integer, Moving Average Length ... + * @param source: Double Array, Specified Array for Calculating Moving Averages ... + * @param buffer: Double Array, Specified Array to Apply Calculated Moving Average on it ... + * @param method: ENUM_MA_METHOD member Specified Moving Average Calculation Method ... + * + * @return ( int ) + */ +int iMAOnBuffer( + const int _rates_total, + const int _prev_calculated, + const int _begin, + const int _period, + const double &_source[], + double &_buffer[], + ENUM_X_MA_METHOD _method = X_MA_MODE_SMA // +) +{ + // + int result = 0; + + // + if ( + _period < 0 || + _rates_total <= 0 || + _prev_calculated < 0 || + _method == X_MA_MODE_NONE || + _prev_calculated > _rates_total) + { + return result; + } + + // + switch (_method) + { + // + case X_MA_MODE_SMA: + result = SimpleMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_EMA: + result = ExponentialMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_LWMA: + result = LinearWeightedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_SMMA: + result = SmoothedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Libraries/x-saherelm.draw.lib.mq5 b/BKPS/14031218/Libraries/x-saherelm.draw.lib.mq5 new file mode 100644 index 0000000..ab7f39b --- /dev/null +++ b/BKPS/14031218/Libraries/x-saherelm.draw.lib.mq5 @@ -0,0 +1,2626 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Draw Library +// -------------------------------------- +// Name: XDraw +// Description: provides Draw abilities ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Global Definitions: Variables, Properties and etc ... + +// +// Retrieve Chart Size in Pixel ... +struct XSize +{ + long width; + long height; + + // + int x; + int y; + int w; + int h; + + // + int wStep; + int hStep; +}; + +// +// Define a Draw Specifications ... +struct XDrawSpecifications +{ + // + // Props ... + + // + bool draw; // Draw or Not ... + + // + int width; // Draw Witdth ... + color clr; // Draw Color ... + ENUM_LINE_STYLE style; // Draw Style ... + + // + bool back; // in the background + bool fill; // fill object if supported + bool selection; // highlight to move + bool rayRight; // line's continuation to the right + bool hidden; // hidden in the object list + long zOrder; // priority for mouse click + + // + string label; // Label ... + color labelColor; // Label Color ... + double labelAngel; // Label Angle ... + string labelFont; // Label Font ... + int labelFontSize; // Label Font Size ... + ENUM_ANCHOR_POINT labelAnchor; // Label Anchor Point ... + + // + // Constructor ... + XDrawSpecifications() + { + Clean(); + } + + // + // Operator ... + void operator=(const XDrawSpecifications &value) + { + // + clr = value.clr; + draw = value.draw; + width = value.width; + style = value.style; + + // + back = value.back; + hidden = value.hidden; + zOrder = value.zOrder; + rayRight = value.rayRight; + selection = value.selection; + + // + fill = value.fill; + + // + label = value.label; + labelColor = value.labelColor; + labelAngel = value.labelAngel; + labelFont = value.labelFont; + labelFontSize = value.labelFontSize; + labelAnchor = value.labelAnchor; + } + + // + // Functions ... + + // + void Clean() + { + // + draw = false; + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + back = false; + hidden = false; + rayRight = false; + selection = false; + fill = false; + + // + zOrder = 0; + + // + label = ""; + labelColor = CLR_NONE; + labelAngel = 0; + labelFont = "Arial"; + labelFontSize = 20; + labelAnchor = ANCHOR_LEFT_UPPER; + + // + ZeroMemory(this); + } + + // + void Label( + string mLabel = "", // Label ... + color mLabelColor = CLR_NONE, // Label Color ... + string mLabelFont = "Arial", // Label Font ... + int mLabelFontSize = 20, // Label Font Size ... + ENUM_ANCHOR_POINT mLabelAnchor = ANCHOR_LEFT_UPPER, // Label Anchor Point ... + double mLabelAngel = 0 // Label Angle ... + ) + { + // + label = mLabel; + labelFont = mLabelFont; + labelColor = mLabelColor; + labelAngel = mLabelAngel; + labelAnchor = mLabelAnchor; + labelFontSize = mLabelFontSize; + } +}; + +// +// Candle Draw Specifications ... +struct XOHCLDrawSpecification +{ + // + // Props ... + XDrawSpecifications openStyle; + XDrawSpecifications highStyle; + XDrawSpecifications closeStyle; + XDrawSpecifications lowStyle; + + // + // Constructors ... + XOHCLDrawSpecification() + { + Clean(); + } + + // + // Operators ... + void operator=(const XOHCLDrawSpecification &value) + { + // + lowStyle = value.lowStyle; + openStyle = value.openStyle; + highStyle = value.highStyle; + closeStyle = value.closeStyle; + } + + // + // Functions ... + + // + void Clean() + { + // + lowStyle.Clean(); + openStyle.Clean(); + highStyle.Clean(); + closeStyle.Clean(); + + // + ZeroMemory(this); + } + + // + void Default() + { + // + // Open ... + openStyle.width = 1; + openStyle.draw = true; + openStyle.clr = clrLime; + openStyle.style = STYLE_SOLID; + openStyle.Label( + "O", + openStyle.clr); + + // + // High ... + highStyle.width = 1; + highStyle.draw = true; + highStyle.clr = clrAqua; + highStyle.style = STYLE_SOLID; + highStyle.Label( + "H", + highStyle.clr); + + // + // Close ... + closeStyle.width = 1; + closeStyle.draw = true; + closeStyle.clr = clrRed; + closeStyle.style = STYLE_SOLID; + closeStyle.Label( + "C", + closeStyle.clr); + + // + // Low ... + lowStyle.width = 1; + lowStyle.draw = true; + lowStyle.clr = clrMagenta; + lowStyle.style = STYLE_SOLID; + lowStyle.Label( + "L", + lowStyle.clr); + } + + // + void Width(int value) + { + // + lowStyle.width = value; + openStyle.width = value; + highStyle.width = value; + closeStyle.width = value; + } + + // + void Style(ENUM_LINE_STYLE value) + { + // + lowStyle.style = value; + openStyle.style = value; + highStyle.style = value; + closeStyle.style = value; + } + + // + void Color(color value) + { + // + lowStyle.clr = value; + openStyle.clr = value; + highStyle.clr = value; + closeStyle.clr = value; + } + + // + void RayRight(bool value) + { + // + lowStyle.rayRight = value; + openStyle.rayRight = value; + highStyle.rayRight = value; + closeStyle.rayRight = value; + } + + // + void Draw(bool value) + { + // + lowStyle.draw = value; + openStyle.draw = value; + highStyle.draw = value; + closeStyle.draw = value; + } + + // + void Back(bool value) + { + // + lowStyle.back = value; + openStyle.back = value; + highStyle.back = value; + closeStyle.back = value; + } + + // + void Fill(bool value) + { + // + lowStyle.fill = value; + openStyle.fill = value; + highStyle.fill = value; + closeStyle.fill = value; + } + + // + void Label(string value) + { + // + lowStyle.Label(value); + openStyle.Label(value); + highStyle.Label(value); + closeStyle.Label(value); + } + + // + void SetLabelPrefix(string value) + { + // + lowStyle.label = value + " " + lowStyle.label; + openStyle.label = value + " " + openStyle.label; + highStyle.label = value + " " + highStyle.label; + closeStyle.label = value + " " + closeStyle.label; + } +}; + +// +string drawPrefix = "X-OBJ"; + +// +// Common Draw Functions ... + +// +// remove drawn objects ... +void RemoveDraws( + string tag = NULL, + long chartId = -1, + int subWindow = -1 // +) +{ + // + // Normalize Args ... + // + if (tag == NULL) + { + tag = drawPrefix; + } + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, tag) >= 0) + { + ObjectDelete(chartId, on); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +bool RemoveDraw( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + string objName = ""; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, name) >= 0) + { + // + objName = on; + break; + } + } + + // + if (StringLen(objName) > 0) + { + result = ObjectDelete(chartId, objName); + } + + // + return result; +} + +// +// Deselect All Draws ... +void DeselectAllDraws() +{ + // + int objs = ObjectsTotal(ChartID(), 0); + for (int o = 0; o < objs; o++) + { + ObjectSetInteger(ChartID(), ObjectName(ChartID(), o, 0), OBJPROP_SELECTED, false); + } + + // + ChartRedraw(); +} + +// +// Check Object Exists ... +bool IsDrawExists( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + result = StringFind(on, name) >= 0; + if (result) + { + break; + } + } + + // + return result; +} + +// +// Find Specific Object Name ... +string FindObjectName( + string suggest, + long chartId = 0, + int subWindow = 0 // +) +{ + // + string result = NULL; + + // + int objectsCount = ObjectsTotal(chartId, subWindow); + if (objectsCount <= 0) + { + return result; + } + + // + for (int i = objectsCount - 1; i >= 0; i--) + { + // + string iObjectName = ObjectName(chartId, i, subWindow); + bool isExists = StringFind(iObjectName, suggest) >= 0; + if (isExists) + { + // + result = iObjectName; + break; + } + } + + // + return result; +} + +// +// Regular Draws ... + +// +// Arrow Functions ... + +// +// Draw an Arrow Object on Chart ... +bool DrawArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // arrow name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const uchar arrowCode = 252, // arrow code + const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position + const color clr = clrAqua, // arrow color + const ENUM_LINE_STYLE style = STYLE_SOLID, // border line style + const int width = 3, // arrow size + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // Order Object ... +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeArrowEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create an arrow ... + result = ObjectCreate(chartID, objName, OBJ_ARROW, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the arrow code ... + ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, arrowCode); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set the arrow color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set the border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set the arrow's size ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the arrow by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is false by default, if you want making it possible to highlight and move the object + // change it to true ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point of Arrow ... +bool MoveArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Delete an arrow ... +bool DeleteArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow" // arrow name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete an arrow ... + result = !ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change the arrow code ... +bool ArrowCodeChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const uchar code = 252 // arrow code +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change the arrow code ... + result = ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, code); + + // + return result; +} + +// +// Change anchor type ... +bool ArrowAnchorChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const ENUM_ARROW_ANCHOR anchor = ANCHOR_TOP // anchor type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor type ... + result = !ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeArrowEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Horizontal Line Functions ... + +// +// Create, Draw the horizontal line ... +bool DrawHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + const int subWindow = 0, // subwindow index + double price = 0, // line price + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the price is not set, set it at the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a horizontal line ... + result = ObjectCreate(chartID, objName, OBJ_HLINE, subWindow, 0, price); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move horizontal line ... +bool MoveHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + double price = 0 // line price +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if the line price is not set, move it to the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move a horizontal line ... + result = ObjectMove(chartID, objName, 0, 0, price); + + // + return result; +} + +// +// Delete a horizontal line ... +bool DeleteHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a horizontal line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Vertical Line Functions ... + +// +// Create the vertical line ... +bool DrawVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + const int subWindow = 0, // subwindow index + datetime time = 0, // line time + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the line time is not set, draw it via the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a vertical line ... + result = ObjectCreate(chartID, objName, OBJ_VLINE, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the vertical line ... +bool MoveVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + datetime time = 0 // line time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if line time is not set, move the line to the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // move the vertical line ... + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete the vertical line ... +bool DeleteVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the vertical line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Rectangle Functions ... + +// +// Create rectangle by the given coordinates ... +bool DrawRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // down first point time + double price1 = 0, // down first point price + datetime time2 = 0, // up second point time + double price2 = 0, // up second point price + const color clr = clrRed, // rectangle color + const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines + const int width = 1, // width of rectangle lines + const bool fill = false, // filling rectangle with color + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Set anchor points' coordinates if they are not set ... + ChangeRectangleEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create a rectangle by the given coordinates ... + result = ObjectCreate( + chartID, + objName, + OBJ_RECTANGLE, + subWindow, + time1, + price1, + time2, + price2 // + ); + if (!result) + { + return result; + } + + // + // Set rectangle color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // Set the style of rectangle lines + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // Set width of the rectangle lines ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // Enable (true) or disable (false) the mode of filling the rectangle ... + ObjectSetInteger(chartID, objName, OBJPROP_FILL, fill); + + // + // Display in the foreground (false) or background (true) ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // Enable (true) or disable (false) the mode of highlighting the rectangle for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + + // + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // Hide (true) or display (false) graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // Set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Successful execution + return result; +} + +// +// Move the rectangle anchor point ...s +bool RectanglePointChange( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete the rectangle ... +bool DeleteRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle" // rectangle name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of rectangle's anchor points and set default +// values for empty ones +void ChangeRectangleEmptyPoints( + datetime &time1, double &price1, + datetime &time2, double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, move it 300 points lower than the first one ... + if (!price2) + { + price2 = price1 - 300 * SymbolInfoDouble(Symbol(), SYMBOL_POINT); + } +} + +// +// RectangleLabel Functions ... + +// +// Create Rectangle Label Object ... +bool DrawRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // width + const int height = 18, // height + const color bgColor = clrWhiteSmoke, // background color + const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const color clr = clrRed, // flat border color (Flat) + const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style + const int lineWidth = 1, // flat border width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a rectangle label + result = ObjectCreate(chartID, objName, OBJ_RECTANGLE_LABEL, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set label coordinates ... + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set label size ... + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set background color ... + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border type ... + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + // set the chart's corner, relative to which point coordinates are defined ... + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set flat border color (in Flat mode) ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set flat border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set flat border width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, lineWidth); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the label by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move Rectangle Label .. +bool MoveRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // move the rectangle label ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Delete the rectangle label ... +bool DeleteRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel" // label name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the label ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change Rectangle Label Size ... +bool ChangeSizeRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int width = 50, // label width + const int height = 18 // label height +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change label size ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change rectangle label border type ... +bool RectLabelChangeBorderType( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const ENUM_BORDER_TYPE border = BORDER_SUNKEN // border type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change border type ... + result = ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + return result; +} + +// +// TrendLine Funcions ... + +// +// Create a trend line by the given coordinates ... +bool DrawTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrYellow, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool rayRight = false, // line's continuation to the right + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeTrendLineEmptyPoints( + time1, + price1, + time2, + price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a trend line by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_TREND, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the line's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move trend line anchor point ... | +bool ChangeTrendLinePoint( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int pointindex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move trend line's anchor point ... + result = ObjectMove(chartID, objName, pointindex, time, price); + + // + return result; +} + +// +// The function deletes the trend line from the chart ... +bool DeleteTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a trend line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of trend line's anchor points and set default ... +// values for empty ones ... +void ChangeTrendLineEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, it is equal to the first point's one ... + if (!price2) + { + price2 = price1; + } +} + +// +// Text Functions ... + +// +// Create and Draw a Text Object ... +bool DrawText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const string text = "Text", // the text itself + const string font = "Arial", // font + const int fontSize = 10, // font size + const color clr = clrRed, // color + const double angle = 0.0, // text slope + const ENUM_ANCHOR_POINT anchor = ANCHOR_CENTER, // anchor type + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeTextEmptyPoint(time, price); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create Text object + result = ObjectCreate(chartID, objName, OBJ_TEXT, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the text ... + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font ... + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size ... + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set the slope angle of the text ... + ObjectSetDouble(chartID, objName, OBJPROP_ANGLE, angle); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the object by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point ... +bool MoveText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // if point position is not set, move it to the current bar having Bid price + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Change the object text ... +bool ChangeText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text ... + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete Text object ... +bool DeleteText( + const long chartID = 0, // chart's ID + const string name = "Text" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeTextEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Fibonacchi Functions ... + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawFibonacci( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // object color + const ENUM_LINE_STYLE style = STYLE_SOLID, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawCustomFibonacci( + // + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + // + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrAqua, // object color + const ENUM_LINE_STYLE style = STYLE_DOT, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, name, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Change Levels Of Fibonacci ... + result = FibonacciLevelsSet( + levels, + values, + colors, + styles, + widths, + descriptions, + chartID, + objName); + + // + // successful execution ... + return result; +} + +// +// Set number of levels and their parameters ... +bool FibonacciLevelsSet( + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // check array sizes ... + result = levels == ArraySize(colors) && + levels == ArraySize(styles) && + levels == ArraySize(widths) && + levels == ArraySize(widths); + if (!result) + { + return result; + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // set the number of levels ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELS, levels); + + // + // set the properties of levels in the loop ... + for (int i = 0; i < levels; i++) + { + // + // level value ... + ObjectSetDouble(chartID, objName, OBJPROP_LEVELVALUE, i, values[i]); + + // + // level color ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELCOLOR, i, colors[i]); + + // + // level style ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELSTYLE, i, styles[i]); + + // + // level width ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELWIDTH, i, widths[i]); + + // + // level description ... + // ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * values[i], 1)); + ObjectSetString(chartID, objName, OBJPROP_LEVELTEXT, i, descriptions[i]); + } + + // + // successful execution ... + return result; +} + +// +// Move Fibonacci Retracement anchor point ... +bool FibonacciPointChange( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete Fibonacci Retracement ... +bool DeleteFibonachi( + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of Fibonacci Retracement anchor points and set +// default values for empty ones ... +void ChangeFibonacciEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the second point's time is not set, it will be on the current bar ... + if (!time2) + { + time2 = TimeCurrent(); + } + + // + // if the second point's price is not set, it will have Bid value ... + if (!price2) + { + price2 = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // if the first point's time is not set, it is located 9 bars left from the second one ... + if (!time1) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time2, 10, temp); + + // + // set the first point 9 bars left from the second one ... + time1 = temp[0]; + } + + // + // if the first point's price is not set, move it 200 points below the second one ... + if (!price1) + { + price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + } +} + +// +// Event Functions ... + +// +// Create an Event ... +bool EventCreate( + const long chartID = 0, // chart's ID + const string name = "Event", // object name + const int subWindow = 0, // subwindow index + const string text = "Content", // event text + datetime time = 0, // anchor point time + const color clr = clrRed, // color + const int width = 1, // point width when highlighted + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectCreate(chartID, objName, OBJ_EVENT, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set event text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set anchor point width if the object is highlighted + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving event by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution + return result; +} + +// +// Change Event object text +bool EventTextChange( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + const string text = "Content" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Move Event object +bool EventMove( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + datetime time = 0 // time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if time is not set, move event to the last bar + if (!time) + { + time = TimeCurrent(); + } + + // + // move the object + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete Event object +bool EventDelete( + const long chartID = 0, // chart's ID + const string name = "Event" // event name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Button Functions ... + +// +// Create the button ... +bool ButtonCreate( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // button width + const int height = 15, // button height + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const string text = "Button", // text + const string font = "Arial", // font + const int fontSize = 8, // font size + const color clr = clrBlack, // text color + const color bgColor = clrLightGray, // background color + const color borderColor = clrNONE, // border color + const bool state = false, // pressed/released + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create the button + result = ObjectCreate(chartID, objName, OBJ_BUTTON, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set button coordinates + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set button size + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set the text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set text color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set background color + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border color + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_COLOR, borderColor); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // set button state + ObjectSetInteger(chartID, objName, OBJPROP_STATE, state); + + // + // enable true or disable false the mode of moving the button by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + return result; +} + +// +// Move the button ... +bool ButtonMove( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // move the button + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Change button size ... +bool ButtonChangeSize( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int width = 50, // button width + const int height = 18 // button height +) +{ + // + bool result = false; + + // + // change the button size + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change corner of the chart for binding the button ... +bool ButtonChangeCorner( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER // chart corner for anchoring +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor corner + result = ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + return result; +} + +// +// Change button text ... +bool ButtonTextChange( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete the button ... +bool ButtonDelete( + const long chartID = 0, // chart's ID + const string name = "Button" // button name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the button + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Chart Style Drawers ... + +// +// Apply Styles On Chart ... +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); +} + +// +// Tools ... + +// +// Retrieve Chart Size ... +bool GetChartSize( + XSize &result, // Holds Result ... + long chartID = 0 // Specified Chart ID ... +) +{ + // + bool mResult = false; + + // + mResult = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, result.width); + if (!mResult) + { + return mResult; + } + + // + mResult = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, result.height); + + // + return mResult; +} diff --git a/BKPS/14031218/Libraries/x-saherelm.x-poi.extensions.lib.ex5 b/BKPS/14031218/Libraries/x-saherelm.x-poi.extensions.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..f14d7011ef5d5b8359ed37995a67b3a712ec18fc GIT binary patch literal 7894 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 +bool ToZone( + T *&source[], + XCZone *&dest[] // +) +{ + // + bool result = false; + + // + Clean(dest); + + // + int count = ArraySize(source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T *item = source[i]; + + // + if (item != NULL) + { + // + Add( + (XCZone *)item, + dest // + ); + } + } + + // + int destCount = ArraySize(dest); + result = IsValidSize(destCount); + + // + return result; +} + +template +bool ToBox( + T *&source[], + XBoxZone &dest[] // +) +{ + // + bool result = false; + + // + Clean(dest); + + // + int count = ArraySize(source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T *item = source[i]; + + // + if (item != NULL) + { + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + item // + ); + + // + if (hasBox) + { + // + AddRef( + iBox, + dest // + ); + } + } + } + + // + int destCount = ArraySize(dest); + result = IsValidSize(destCount); + + // + return result; +} + +template +int GetOldest( + T *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone boxes[]; + bool isConverted = ToBox( + source, + boxes // + ); + if (!isConverted) + { + return result; + } + + // + int boxesCount = ArraySize(boxes); + + // + if (count != boxesCount) + { + return result; + } + + // + result = GetOldest(boxes); + + // + Clean(boxes); + + // + return result; +} + +template +int GetYoungest( + T *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone boxes[]; + bool isConverted = ToBox( + source, + boxes // + ); + if (!isConverted) + { + return result; + } + + // + int boxesCount = ArraySize(boxes); + + // + if (count != boxesCount) + { + return result; + } + + // + result = GetYoungest(boxes); + + // + Clean(boxes); + + // + return result; +} + +template +int GetLowest( + T *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone boxes[]; + bool isConverted = ToBox( + source, + boxes // + ); + if (!isConverted) + { + return result; + } + + // + int boxesCount = ArraySize(boxes); + + // + if (count != boxesCount) + { + return result; + } + + // + result = GetLowest(boxes); + + // + Clean(boxes); + + // + return result; +} + +template +int GetHighest( + T *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone boxes[]; + bool isConverted = ToBox( + source, + boxes // + ); + if (!isConverted) + { + return result; + } + + // + int boxesCount = ArraySize(boxes); + + // + if (count != boxesCount) + { + return result; + } + + // + result = GetHighest(boxes); + + // + Clean(boxes); + + // + return result; +} + +template +bool IsSame( + T *source, + T *dest // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = sourceBox.IsSame(destBox); + + // + return result; +} + +template +bool IsSameDiff( + T *source, + F *dest // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = sourceBox.IsSame(destBox); + + // + return result; +} + +template +bool IsBelow( + T *source, + T *dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxBelow( + sourceBox, + destBox, + ignoreInside // + ); + + // + return result; +} + +template +bool IsBelowDiff( + T *source, + F *dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxBelow( + sourceBox, + destBox, + ignoreInside // + ); + + // + return result; +} + +template +bool IsAbove( + T *source, + T *dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxAbove( + sourceBox, + destBox, + ignoreInside // + ); + + // + return result; +} + +template +bool IsAboveDiff( + T *source, + F *dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxAbove( + sourceBox, + destBox, + ignoreInside // + ); + + // + return result; +} + +template +bool IsInside( + T *source, + T *dest // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxInside( + sourceBox, + destBox // + ); + + // + return result; +} + +template +bool IsInsideOr( + T *source, + T *dest // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxInsideOr( + sourceBox, + destBox // + ); + + // + return result; +} + +template +bool IsInsideDiff( + T *source, + F *dest, + bool forceSideOut = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxInside( + sourceBox, + destBox, + forceSideOut // + ); + + // + return result; +} + +template +bool IsInsideOrDiff( + T *source, + F *dest, + bool forceSideOut = false // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + XBoxZone destBox; + result = ToBox( + destBox, + dest // + ); + if (!result) + { + return result; + } + + // + result = IsBoxInsideOr( + sourceBox, + destBox // + ); + + // + return result; +} + +template +bool FindIndex( + int &index, + T *item, + T *&items[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + XBoxZone itemBox; + result = ToBox( + itemBox, + item // + ); + if (!result) + { + return result; + } + + // + XBoxZone itemsBox[]; + result = ToBox( + items, + itemsBox // + ); + if (!result) + { + return result; + } + + // + result = FindBoxIndex( + index, + itemBox, + itemsBox // + ); + + // + return result; +} + +template +bool IsInside( + double value, + T *source // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + result = IsInsideBox( + value, + sourceBox // + ); + + // + return result; +} + +template +bool IsAbove( + double value, + T *source // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + result = IsAboveBox( + value, + sourceBox // + ); + + // + return result; +} + +template +bool IsBelow( + double value, + T *source // +) +{ + // + bool result = false; + + // + XBoxZone sourceBox; + result = ToBox( + sourceBox, + source // + ); + if (!result) + { + return result; + } + + // + result = IsBelowBox( + value, + sourceBox // + ); + + // + return result; +} + +/** + * Find Specified Box Index inside a Collection of Boxes ... + * + * @param box: XBoxZone instance Reference ... + * @param boxes: XBoxZone instance Reference Collection ... + * + * @return ( int ) + */ +bool FindBoxIndex( + int &index, + XBoxZone &box, + XBoxZone &boxes[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + int count = ArraySize(boxes); + result = box.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = boxes[i]; + + // + bool isSame = box.IsSame(iBox); + if (isSame) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +/** + * Check Source Box is Below Dest ... + * + * @param source: XBoxZone instance Reference ... + * @param dest: XBoxZone instance Reference ... + * @param ignoreInside: bool ... + * + * @return ( bool ) + */ +bool IsBoxBelow( + XBoxZone &source, + XBoxZone &dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid() && + !source.IsSame(dest); + if (!result) + { + return result; + } + + // + if (!ignoreInside) + { + result = source.upper < dest.lower; + } + else + { + result = (source.upper < dest.lower || + source.upper >= dest.upper) && + source.lower < dest.lower; + } + + // + return result; +} + +/** + * Check Source Box is Above Dest ... + * + * @param source: XBoxZone instance Reference ... + * @param dest: XBoxZone instance Reference ... + * @param ignoreInside: bool ... + * + * @return ( bool ) + */ +bool IsBoxAbove( + XBoxZone &source, + XBoxZone &dest, + bool ignoreInside = false // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid() && + !source.IsSame(dest); + if (!result) + { + return result; + } + + // + if (!ignoreInside) + { + result = source.lower > dest.upper; + } + else + { + result = (source.lower > dest.upper || + source.lower <= dest.upper) && + source.upper > dest.upper; + } + + // + return result; +} + +/** + * Check Source Box is Inside Dest ... + * + * @param source: XBoxZone instance Reference ... + * @param dest: XBoxZone instance Reference ... + * @param forceSideOut: bool, force check Box has One Side Out ... + * @param ignoreSideOut: bool, Accept if source Box one Side is out of Dest Box ... + * + * @return ( bool ) + */ +bool IsBoxInside( + XBoxZone &source, + XBoxZone &dest, + bool forceSideOut = false, // + bool ignoreSideOut = true // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid() && + !source.IsSame(dest); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(dest.dir); + + // + if (!forceSideOut) + { + // + if (ignoreSideOut) + { + // + result = source.lower >= dest.lower && + source.upper <= dest.upper; + } + else + { + result = source.lower >= dest.lower || + source.upper <= dest.upper; + } + } + else + { + // + bool hasSideIn = + isBullish + ? source.lower >= dest.lower + : source.upper <= dest.upper; + bool hasSideOut = + isBullish + ? source.upper >= dest.upper + : source.lower <= dest.lower; + result = + hasSideIn && + hasSideOut; + } + + // + return result; +} + +/** + * Detect source BoX is Inside Dest Box or Have a Side Out on it ... + * + * @param source: XBoxZone instance, source box which checks by dest ... + * @param dest: XBoxZone instance, dest Box which compares source with it ... + * + * @return ( bool ) + */ +bool IsBoxInsideOr( + XBoxZone &source, + XBoxZone &dest // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + dest.IsValid() && + !source.IsSame(dest); + if (!result) + { + return result; + } + + // + bool isLowerInside = + source.lower > dest.lower && + source.lower < dest.upper && + (source.upper < dest.upper || + source.upper > dest.upper); + bool isUpperInside = + source.upper < dest.upper && + source.upper > dest.lower && + (source.lower > dest.lower || + source.lower < dest.lower); + result = + isLowerInside || + isUpperInside; + + // + return result; +} + +/** + * Check Value is Inside Specified Box ... + * + * @param value: double ... + * @param box: XCBozZone instance Reference ... + * + * @return ( bool ) + */ +bool IsInsideBox( + double value, + XBoxZone &box // +) +{ + // + bool result = false; + + // + result = value > 0 && + box.IsValid() && + value <= box.upper && + value >= box.lower; + + // + return result; +} + +/** + * Check Value is Above Specified Box ... + * + * @param value: double ... + * @param box: XCBozZone instance Reference ... + * + * @return ( bool ) + */ +bool IsAboveBox( + double value, + XBoxZone &box // +) +{ + // + bool result = false; + + // + result = value > 0 && + box.IsValid() && + value > box.upper; + + // + return result; +} + +/** + * Check Value is Below Specified Box ... + * + * @param value: double ... + * @param box: XCBozZone instance Reference ... + * + * @return ( bool ) + */ +bool IsBelowBox( + double value, + XBoxZone &box // +) +{ + // + bool result = false; + + // + result = value > 0 && + box.IsValid() && + value < box.lower; + + // + return result; +} + +/** + * Check a Box is Used or not ... + * + * @param box: XBoxZone instance Reference ... + * @param fromIndex: int ... + * @param toIndex: int + * @param forPeriod: Specified Period ... + * + * @return ( bool ) + */ +bool IsBoxUsed( + XBoxZone &box, + int fromIndex, + int toIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // +) +{ + // + bool result = false; + + // + if (toIndex < 0) + { + toIndex = 0; + } + + // + result = + // + box.IsValid() && + fromIndex > 0 && + fromIndex > toIndex + // + ; + if (!result) + { + return result; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = box.period; + } + + // + ENUM_X_DIRECTION forDir = box.dir; + bool isBullish = IsBullish(forDir); + + // + for (int i = fromIndex; i >= toIndex; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + box.symbol, + forPeriod, + i // + ); + + // + bool isTouched = + isBullish + ? iBar.high > box.lower + : iBar.low < box.upper; + if (!isTouched) + { + continue; + } + + // + iBar.Clean(); + result = false; + break; + } + + // + return result; +} + +/** + * Find an Inside Box of source in a Collection ... + * + * @param index: int, Founded Index ... + * @param source: XBoxZone instance ... + * @param dest: XBoxZone instance Collection ... + * + * @return ( bool ) + */ +bool HasInsideBox( + int &index, + XBoxZone &source, + XBoxZone &dest[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + result = source.IsValid() && + HasChild(dest); + + // + int count = ArraySize(dest); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = dest[i]; + + // + bool isInside = !iBox.IsSameAs(source) && + IsBoxInsideOr( + iBox, + source // + ); + if (isInside) + { + // + index = i; + iBox.Clean(); + + // + break; + } + + // + iBox.Clean(); + } + + // + result = IsValidIndex(index); + + // + return result; +} + +bool IsValidBox( + XBoxZone &box, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // +) +{ + // + bool result = false; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = box.period; + } + + // + int fromIndex = iBarShift( + box.symbol, + forPeriod, + box.from // + ); + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + XOHCL iBar; + bool isBullish = box.IsBullish(); + for (int i = barIndex; i < fromIndex; i++) + { + // + result = iBar.Init( + box.symbol, + forPeriod, + i // + ); + if (!result) + { + break; + } + + // + result = + isBullish + ? iBar.GetDown() > box.lower + : iBar.GetUp() < box.upper; + if (!result) + { + break; + } + + // + iBar.Clean(); + } + + // + iBar.Clean(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCOrderBlock *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = item.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCFVG *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = item.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCSupportZone *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = X_DIRECTION_BULLISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCResistanceZone *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = X_DIRECTION_BEARISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCSupplyZone *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = X_DIRECTION_BEARISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XCDemandZone *item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item != NULL && + item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.To(); + box.from = item.From(); + box.upper = item.Upper(); + box.lower = item.Lower(); + box.symbol = item.GetSymbol(); + box.period = item.GetPeriod(); + box.type = item.TypeAsString(); + box.dir = X_DIRECTION_BULLISH; + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XConsolidationZone &item // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + box.to = item.to; + box.dir = item.dir; + box.from = item.from; + box.upper = item.upper; + box.lower = item.lower; + box.symbol = item.symbol; + box.period = item.period; + box.type = IsBullish(item.dir) + ? ToString(X_BULLISH_CONSOLIDATION_ZONE) + : ToString(X_BEARISH_CONSOLIDATION_ZONE); + + // + result = box.IsValid(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +int ToBox( + XConsolidationZone &source[], + XBoxZone &dest[] // +) +{ + // + int result = 0; + + // + Clean(dest); + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XConsolidationZone iZone = source[i]; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + + // + if (hasBox) + { + // + AddRef( + iBox, + dest // + ); + } + + // + iBox.Clean(); + iZone.Clean(); + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Get Oldest Box Index ... + * + * @param source: XBoxZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetOldest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from > iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Box Index ... + * + * @param source: XBoxZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetYoungest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from < iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Box Index ... + * + * @param source: XBoxZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetHighest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.upper < iBox.upper; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Box Index ... + * + * @param source: XBoxZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetLowest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.lower > iBox.lower; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + selected.Clean(); + + // + return result; +} + +// +// +// + +/** + * Get Oldest Index ... + * + * @param source: XConsolidationZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetOldest( + XConsolidationZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from > iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index ... + * + * @param source: XConsolidationZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetYoungest( + XConsolidationZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from < iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Index ... + * + * @param source: XConsolidationZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetHighest( + XConsolidationZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.upper < iBox.upper; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Index ... + * + * @param source: XConsolidationZone instance Reference Collection ... + * + * @return ( int ) + */ +int GetLowest( + XConsolidationZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.lower > iBox.lower; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +// +// +// + +// +template +void SortZones( + T *&source[], + ENUM_X_DIRECTION forDir, + bool ignoreInside = true // +) +{ + // + int idx = -1; + int count = 0; + bool has = false; + + // + has = HasDirection(forDir); + if (!has) + { + return; + } + + // + bool isBullish = IsBullish(forDir); + + // + count = ArraySize(source); + has = IsValidSize(count); + if (!has) + { + return; + } + + // + T *tmpItems[]; + T *last = NULL; + bool hasLast = false; + while (HasChild(source)) + { + // + if (!hasLast) + { + // + idx = GetOldest(source); + hasLast = IsValidIndex(idx); + if (hasLast) + { + // + last = source[idx]; + ArrayRemove( + source, + idx, + 1 // + ); + + // + Add( + last, + tmpItems // + ); + } + + // + count = ArraySize(source); + has = IsValidSize(count); + if (!has) + { + // + ZeroMemory(last); + break; + } + } + if (!hasLast) + { + // + ZeroMemory(last); + break; + } + + // + T *item = NULL; + idx = GetOldest(source); + has = IsValidIndex(idx); + if (!has) + { + // + ZeroMemory(last); + ZeroMemory(item); + break; + } + item = source[idx]; + ArrayRemove( + source, + idx, + 1 // + ); + + // + bool isAbove = IsAbove( + item, + last, + ignoreInside // + ); + + // + bool isBelow = IsBelow( + item, + last, + ignoreInside // + ); + + // + has = + isBullish + ? isAbove + : isBelow; + if (has) + { + // + Add( + item, + tmpItems // + ); + + // + last = item; + hasLast = item != NULL; + } + } + + // + Clean(source); + Copy( + tmpItems, + source // + ); + + // + Clean(tmpItems); +} + +/** + * Extract all Zones Which provided bar is Inside it ... + * + * @return ( int ) + */ +template +int ExtractInsideZones( + XOHCL &bar, // Bar ... + T *&zones[], // Source of Zones ... + T *&dest[] // Dest (all inside Zones) ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int count = ArraySize(zones); + bool isValid = bar.IsValid() && + IsValidSize(count); + if (!isValid) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T *iZone = zones[i]; + + // + bool isHighInside = IsInside( + bar.high, + iZone // + ); + + // + bool isLowInside = IsInside( + bar.low, + iZone // + ); + + // + bool isInside = + isLowInside && + isHighInside; + + // + if (isInside) + { + // + Add( + iZone, + dest // + ); + } + + // + ZeroMemory(iZone); + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Add Specific Item into a Collection Reference only if it's not Exists ... + * + * @return ( bool ) + */ +template +bool AddIfNotExists( + T *item, + T *&items[] // +) +{ + // + bool result = false; + + // + result = item != NULL; + if (!result) + { + return result; + } + + // + int before = ArraySize(items); + + // + int idx = FindIndex( + item, + items // + ); + bool has = IsValidIndex(idx); + result = !has; + if (!result) + { + return result; + } + + // + Add( + item, + items // + ); + + // + int after = ArraySize(items); + + // + result = after > before; + + // + return result; +} +bool AddIfNotExists( + XConsolidationZone &item, + XConsolidationZone &items[] // +) +{ + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + int before = ArraySize(items); + + // + int idx = FindIndex( + item, + items // + ); + bool has = IsValidIndex(idx); + result = !has; + if (!result) + { + return result; + } + + // + AddRef( + item, + items // + ); + + // + int after = ArraySize(items); + + // + result = after > before; + + // + return result; +} + +/** + * Add items Collection reference Members into source Collection only if it's not Exists ...alignas + * @return ( int ) + */ +template +int AddIfNotExists( + T *&items[], + T *&sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items); + if (!has) + { + return result; + } + + // + int before = ArraySize(sources); + + // + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + has = AddIfNotExists( + items[i], + sources // + ); + } + + // + int after = ArraySize(sources); + + // + result = after > before; + + // + return result; +} +int AddIfNotExists( + XConsolidationZone &items[], + XConsolidationZone &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items); + if (!has) + { + return result; + } + + // + int before = ArraySize(sources); + + // + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + has = AddIfNotExists( + items[i], + sources // + ); + } + + // + int after = ArraySize(sources); + + // + result = after > before; + + // + return result; +} + +/** + * Update to Time of Specifiex Collection ... + * + * @param items: XOBFVG instance Collection ... + * @param value: datetime ... + */ +template +void SpecifiedUpdateTo( + T *&items[], + datetime value = NULL // +) +{ + // + value = NormalizeTime(value); + + // + int count = ArraySize(items); + bool has = HasChild(items); + if (!has) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + items[i].To(value); + } +} + +// +template +int FilterZones( + // + T *&source[], + // + ENUM_X_DIRECTION forDir, + ENUM_TIMEFRAMES forPeriod = NULL, + datetime after = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false, + // + bool applySort = false, + // + bool ignoreInside = true + // +) +{ + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + has = HasDirection(forDir); + if (!has) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + count = ArraySize(source); + has = IsValidSize(count); + if (!has) + { + return result; + } + + // + T *tmpZones[]; + XOHCL passedBar; + bool isPassed = false; + for (int i = 0; i < count; i++) + { + // + T *iZone = source[i]; + + // + // Apply after Filter ... + isPassed = + !IsValid(after) + ? true + : iZone.From() >= after; + if (!isPassed) + { + // + ZeroMemory(iZone); + continue; + } + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + forDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + forDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + forDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + forDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + tmpZones // + ); + if (has) + { + // + ZeroMemory(iZone); + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + tmpZones // + ); + } + + // + Clean(source); + + // + has = HasChild(tmpZones); + if (!has) + { + // + Clean(tmpZones); + passedBar.Clean(); + return result; + } + + // + // Apply Sorting ... + if (applySort) + { + // + T *last = NULL; + bool hasLast = false; + while (HasChild(tmpZones)) + { + // + idx = GetYoungest(tmpZones); + hasLast = IsValidIndex(idx); + if (hasLast) + { + // + last = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + + // + Add( + last, + source // + ); + } + + // + has = HasChild(tmpZones); + if (!has) + { + break; + } + + // + T *zone = NULL; + bool hasZone = false; + idx = GetYoungest(tmpZones); + hasZone = IsValidIndex(idx); + if (hasZone) + { + // + zone = tmpZones[idx]; + ArrayRemove( + tmpZones, + idx, + 1 // + ); + } + if (!hasZone) + { + // + ZeroMemory(zone); + continue; + } + + // + bool isAbove = IsAbove( + zone, + last, + ignoreInside // + ); + + // + bool isBelow = IsBelow( + zone, + last, + ignoreInside // + ); + + // + isPassed = + isBullish + ? isAbove + : isBelow; + if (!isPassed) + { + // + ZeroMemory(zone); + continue; + } + + // + Add( + zone, + source // + ); + } + } + else + { + // + Copy( + tmpZones, + source // + ); + } + + // + result = ArraySize(source); + + // + return result; +} + +// +// +// + +/** + * Detect Nearest Price Out of Specified Box ... + * + * @param box: XBoxZone instance Reference ... + * @param outSideBar: XOHCL instance Reference which Represents Out Side Bar if Exists ... + * @param forPeriod: ENUM_TIMEFRAMES member which provides time frame of Out Bar, if not Provides used box Period as Default ... + * @param forDir: ENUM_X_DIRECTION member which Specified outSide Direction, use Box Dir as Default ... + * @param forceBodyIn: bool value which Specifyed Body Breakes or not, Default is false ... + * @param barIndex: integer value which Specified Start Bar Index, Default is 0 ... + * + * @return ( bool ) + */ +bool DetectBoxNearestPriceOut( + XBoxZone &box, + XOHCL &outSideBar, + ENUM_TIMEFRAMES forPeriod = NULL, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, + bool forceBodyIn = false, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + outSideBar.Clean(); + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = box.period; + } + + // + if (!HasDirection(forDir)) + { + forDir = box.dir; + } + + // + bool isBullish = IsBullish(forDir); + + // + int fromIndex = iBarShift( + box.symbol, + box.period, + box.from // + ); + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + XOHCL iBar; + XOHCL iPBar; + bool has = false; + for (int i = barIndex; i < fromIndex; i++) + { + // + has = iBar.Init( + box.symbol, + forPeriod, + i // + ); + if (!has) + { + continue; + } + + // + has = iBar.GetPreviousBar(iPBar); + if (!has) + { + continue; + } + + // + bool isInsideFromLower = + iBar.high < box.lower && + iPBar.high > box.lower; + + // + bool isInsideFromUpper = + iBar.low > box.upper && + iPBar.low < box.upper; + + // + bool isInsideBodyFromLower = + iPBar.GetUp() > box.lower; + + // + bool isInsideBodyFromUpper = + iPBar.GetDown() < box.upper; + + // + result = + isBullish + ? (!forceBodyIn + ? isInsideFromLower + : isInsideFromLower && + isInsideBodyFromLower) + : (!forceBodyIn + ? isInsideFromUpper + : isInsideFromUpper && + isInsideBodyFromUpper); + if (result) + { + // + outSideBar = iBar; + break; + } + } + + // + iBar.Clean(); + iPBar.Clean(); + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031218/Libraries/x-saherelm.x-poi.lib.ex5 b/BKPS/14031218/Libraries/x-saherelm.x-poi.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..d995ce7ca3c294ae5655cb2a252fa9c8df4b0be5 GIT binary patch literal 7792 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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Libraries/x-saherelm.x-poi.lib.mq5 b/BKPS/14031218/Libraries/x-saherelm.x-poi.lib.mq5 new file mode 100644 index 0000000..def6c2c --- /dev/null +++ b/BKPS/14031218/Libraries/x-saherelm.x-poi.lib.mq5 @@ -0,0 +1,5365 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright `023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include + +// +// Definitions ... + +// +// All Available POI(s) ... +enum ENUM_XPOIS +{ + // + X_POI_NONE, + // + X_POI_TICKS_ZONES, // Ticks Zone ... + // + // Trading Day ... + X_POI_TRADING_DAY, // Trading Day ... + // + // Market Session ... + X_POI_MARKET_SESSION, // Market Session ... + // + // Momentum Bar ... + X_POI_MOMENTUM_BAR, // Momentum Bar ... + // + // Rejection Bar ... + X_POI_REJECTION_BAR, // Rejection Bar ... + // + // Swings ... + X_POI_SWING_HIGH, // Simple Swing High ... + X_POI_SWING_LOW, // Simple Swing Low ... + // + // Support nad Resistance ... + X_POI_SUPPORT_ZONE, // Support Zone ... + X_POI_RESISTANCE_ZONE, // Resistance Zone ... + // + // Supply and Demand Zones ... + X_POI_SUPPLY_ZONE, // Supply Zone ... + X_POI_DEMAND_ZONE, // Demand Zone ... + // + // Order Blocks ... + X_POI_BULLISH_ORDERBLOCK, // Bullish Order Block ... + X_POI_BEARISH_ORDERBLOCK, // Bearish Order Block ... + // + // Fair Value Gaps ... + X_POI_BULLISH_FVG, // Bullish Order Block ... + X_POI_BEARISH_FVG, // Bearish Order Block ... + // + X_BULLISH_CONSOLIDATION_ZONE, + X_BEARISH_CONSOLIDATION_ZONE, +}; + +// +// Event Types ... +enum ENUM_XPOI_EVENTS +{ + // + X_POI_EVENT_NONE, + // + // Trading Days ... + X_TRADE_DAY_FIRST_BAR, // Trading Day First Bar ... + X_TRADE_DAY_LAST_BAR, // Trading Day Last Bar ... + // + // Session ... + X_SESSION_FIRST_BAR, // Session First Bar ... + X_SESSION_LAST_BAR, // Session Last Bar ... + // + // Momentum Bar ... + X_BULLISH_MOMENTUM_BAR_DETECTED, + X_BEARISH_MOMENTUM_BAR_DETECTED, + // + // Rejection Bar ... + X_BULLISH_REJECTION_BAR_DETECTED, + X_BEARISH_REJECTION_BAR_DETECTED, + // + // Swings ... + X_SWING_HIGH_DETECTED, + X_SWING_LOW_DETECTED, + // + // Support nad Resistance ... + X_SUPPORT_ZONE_DETECTED, // Support Zone ... + X_RESISTANCE_ZONE_DETECTED, // Resistance Zone ... + // + // Supply nad Demand ... + X_SUPPLY_ZONE_DETECTED, // Supply Zone ... + X_DEMAND_ZONE_DETECTED, // Demand Zone ... + // + // Order Blocks ... + X_BULLISH_ORDERBLOCK_DETECTED, // Bullish Order Block ... + X_BEARISH_ORDERBLOCK_DETECTED, // Bearish Order Block ... + // + // Fair Value Gaps ... + X_BULLISH_FVG_DETECTED, // Bullish Fair Value GapÙ‘ ... + X_BEARISH_FVG_DETECTED, // Bearish Fair Value GapÙ‘ ... + X_BULLISH_CONSOLIDATION_ZONE_DETECTED, + X_BEARISH_CONSOLIDATION_ZONE_DETECTED, +}; + +// +enum ENUM_XZONE_STATE +{ + XZONE_STATE_NONE, + XZONE_STATE_PASSED, + XZONE_STATE_FAILED, + XZONE_STATE_IGNORED, +}; + +// +// Forext Sessions ... +enum ENUM_XSESSION +{ + X_TOKYO, + X_SYDNEY, + X_LONDON, + X_NEW_YORK, + X_FRANKFORT, +}; + +/** + * Converts ENUM_XPOI value to String Representation ... + * + * @param value: ENUM_XPOI member ... + * + * @return ( string ) + */ +string ToString(ENUM_XPOIS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POI_TRADING_DAY: + result = "XTDAY"; + break; + + // + case X_POI_MARKET_SESSION: + result = "XMSESS"; + break; + + // + case X_POI_MOMENTUM_BAR: + result = "XMNTMB"; + break; + + // + case X_POI_REJECTION_BAR: + result = "XRJCTB"; + break; + + // + case X_POI_SWING_HIGH: + result = "XSPH"; + break; + + // + case X_POI_SWING_LOW: + result = "XSPL"; + break; + + // + case X_POI_SUPPORT_ZONE: + result = "XSUP"; + break; + + // + case X_POI_RESISTANCE_ZONE: + result = "XRES"; + break; + + // + case X_POI_SUPPLY_ZONE: + result = "XSUPPLY"; + break; + + // + case X_POI_DEMAND_ZONE: + result = "XDEMAND"; + break; + + // + case X_POI_BULLISH_ORDERBLOCK: + result = "XBULLOB"; + break; + + // + case X_POI_BEARISH_ORDERBLOCK: + result = "XBEAROB"; + break; + + // + case X_POI_BULLISH_FVG: + result = "XBULLFVG"; + break; + + // + case X_POI_BEARISH_FVG: + result = "XBEARFVG"; + break; + + // + case X_POI_TICKS_ZONES: + result = "XTKSZ"; + break; + + // + case X_BULLISH_CONSOLIDATION_ZONE: + result = "XBULLCZ"; + break; + + // + case X_BEARISH_CONSOLIDATION_ZONE: + result = "XBEARCZ"; + break; + } + + // + return result; +} + +/** + * Converts ENUM_XSESSION value to String Representation ... + * + * @param value: ENUM_XSESSION member ... + * + * @return ( string ) + */ +string ToString(ENUM_XSESSION value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SYDNEY: + result = "Sydney"; + break; + + // + case X_TOKYO: + result = "Tokyo"; + break; + + // + case X_FRANKFORT: + result = "FrankGurt"; + break; + + // + case X_LONDON: + result = "London"; + break; + + // + case X_NEW_YORK: + result = "NewYork"; + break; + } + + // + return result; +} + +/** + * Generate General Event Messages ... + * + * @param value: ENUM_XPOI_EVENTS member ... + * + * @return ( string ) + */ +string ToString(ENUM_XPOI_EVENTS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_TRADE_DAY_FIRST_BAR: + result = "First Bar of Day"; + break; + + // + case X_TRADE_DAY_LAST_BAR: + result = "Last Bar of Day"; + break; + + // + case X_SESSION_FIRST_BAR: + result = "First Bar of Session"; + break; + + // + case X_SESSION_LAST_BAR: + result = "Last Bar of Session"; + break; + + // + case X_BULLISH_MOMENTUM_BAR_DETECTED: + result = "Bullish Momentum Bar Detected"; + break; + + // + case X_BEARISH_MOMENTUM_BAR_DETECTED: + result = "Bearish Momentum Bar Detected"; + break; + + // + case X_BULLISH_REJECTION_BAR_DETECTED: + result = "Bullish Rejection Bar Detected"; + break; + + // + case X_BEARISH_REJECTION_BAR_DETECTED: + result = "Bearish Rejection Bar Detected"; + break; + + // + case X_SWING_HIGH_DETECTED: + result = "Swing High Detected"; + break; + + // + case X_SWING_LOW_DETECTED: + result = "Swing Low Detected"; + break; + + // + case X_SUPPORT_ZONE_DETECTED: + result = "Support Zone Detected"; + break; + + // + case X_RESISTANCE_ZONE_DETECTED: + result = "Resistance Zone Detected"; + break; + + // + case X_SUPPLY_ZONE_DETECTED: + result = "Supply Zone Detected"; + break; + + // + case X_DEMAND_ZONE_DETECTED: + result = "Demand Zone Detected"; + break; + + // + case X_BULLISH_ORDERBLOCK_DETECTED: + result = "Bullish Order Block Detected"; + break; + + // + case X_BEARISH_ORDERBLOCK_DETECTED: + result = "Bearish Orer Block Detected"; + break; + + // + case X_BULLISH_FVG_DETECTED: + result = "Bullish FVG Detected"; + break; + + // + case X_BEARISH_FVG_DETECTED: + result = "Bearish FVg Detected"; + break; + } + + // + return result; +} + +// +// Implementation ... + +// +// Base POI Model Class ... +class XCBasePOI : public XCBase +{ + // + public: + // + + // + // Constructor ... + void XCBasePOI() + { + // + Clean(); + + // + mSep = "_"; + mLineSep = "\n"; + } + + // + // Deconstructor ... + void ~XCBasePOI() + { + Clean(); + } + + // + // Virtual ... + + /** + * Cleanup ... + */ + virtual void Clean() + { + mType = X_POI_NONE; + } + + /** + * Validate ... + * + * @return ( virtual bool ) + */ + virtual bool IsValid() + { + return false; + } + + /** + * Retrieve POI Type ... + * + * @return ( virtual ENUM_XPOIS member ) + */ + virtual ENUM_XPOIS Type() + { + return mType; + } + + /** + * Retrieve POI Type ... + * + * @return ( virtual string ) + */ + virtual string TypeAsString() + { + return ToString(mType); + } + + /** + * Retrieve POI Tag ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + return NULL; + } + + /** + * Retrieve POI Tooltip ... + * + * @return ( virtual string ) + */ + virtual string GetTooltip() + { + return NULL; + } + + // + protected: + // + // Props ... + string mSep; // Separator ... + string mLineSep; // Line Separator ... + ENUM_XPOIS mType; // Type ... + + // + private: + // +}; + +// +typedef void (*TOnPOIEvent)(ENUM_XPOI_EVENTS event, + XCBasePOI *param // +); + +// +// Zone POI Class ... +class XCZone : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCZone() + { + } + + // + // Deconstructor ... + void ~XCZone() + { + } + + // + // Tools ... + + // + // Getter(s) / Setter(s) ... + + /** + * Get Zone Upper Boundary ... + * + * @return ( double ) + */ + double Upper() + { + return mUpper; + } + + /** + * Set Zone Upper Boundary ... + */ + void Upper(double value) + { + mUpper = value; + } + + /** + * Get Zone Lower Boundary ... + * + * @return ( double ) + */ + double Lower() + { + return mLower; + } + + /** + * Set Zone Lower Boundary ... + */ + void Lower(double value) + { + mLower = value; + } + + /** + * Retrieve Zone Range ... + * + * @return ( double ) + */ + double Range() + { + // + double result = 0; + + // + double upper = Upper(); + double lower = Lower(); + + // + if (upper > 0 && lower > 0 && upper > lower) + { + result = upper - lower; + } + + // + return result; + } + + double RangePercent() + { + // + double result = 0; + + // + double range = Range(); + if (range > 0) + { + result = range / 100; + } + + // + return result; + } + + // + // Virtuals ... + + /** + * Get Zone Start Date ... + * + * @return ( virtual datetime ) + */ + virtual datetime From() + { + return NULL; + } + + /** + * Get Zone End Date ... + * + * @return ( virtual datetime ) + */ + virtual datetime To() + { + return NULL; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + // Validators ... + + /** + * Validate Upper and Lower of Zone ... + * + * @return ( bool ) + */ + bool IsValidBoundary() + { + // + bool result = false; + + // + result = + // + mUpper > 0 && + mLower > 0 && + mUpper >= mLower + // + ; + + // + return result; + } + + /** + * Check From Date of Zone is Valid ... + * + * @return ( bool ) + */ + bool IsValidFrom() + { + // + bool result = false; + + // + datetime from = From(); + result = IsSpecifiedValid(from); + + // + return result; + } + + // + protected: + // + // Props ... + double mUpper; // Zone Upper ... + double mLower; // Zone Lower ... + + // + private: + // + // Props ... + + // +}; + +// +// From To Zone ... +class XCFromToZone : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCFromToZone() + { + } + + // + // Deconstructor ... + void ~XCFromToZone() + { + } + + // + // Tools ... + + bool InitFromTo( + ENUM_XPOIS type, + string title, + datetime from // + ) + { + // + bool result = false; + + // + result = type != X_POI_NONE && + IsSpecifiedValid(from) && + IsSpecifiedValid(title); + + // + mType = type; + mFrom = from; + mTitle = title; + mTo = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + bool InitFromTo( + ENUM_XPOIS type, + string title, + datetime from, + datetime to // + ) + { + // + bool result = false; + + // + result = IsValid(); + + // + result = InitFromTo( + type, + title, + from // + ); + if (!result) + { + return result; + } + + // + to = NormalizeTime(to); + mTo = to; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Zone Start Time ... + * + * @return ( datetime ) + */ + datetime From() + { + return mFrom; + } + + /** + * Set Zone Start Time ... + * + * @param value: Datetime + */ + void From(datetime value) + { + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Get Zone End Time ... + * + * @return ( datetime ) + */ + datetime To() + { + return mTo; + } + + /** + * Set Zone End Time ... + * + * @param value: Datetime + */ + void To(datetime value) + { + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Get Title ... + * + * @return ( string ) + */ + string Title() + { + return mTitle; + } + + /** + * Set Title ... + * + * @param value: String ... + */ + // void Title(string value) + // { + // mTitle = value; + // } + + // + // Overrides ... + + void Clean() override + { + // + mTo = NULL; + mFrom = NULL; + mType = X_POI_NONE; + } + + bool IsValid() override + { + // + bool result = false; + + // + result = + // + mType != X_POI_NONE && + IsSpecifiedValid(mTo) && + IsSpecifiedValid(mFrom) && + IsSpecifiedValid(mTitle) + // + ; + + // + return result; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = TypeAsString() + mSep + ToString(From()) + mSep + Title(); + hash = ToMD5(hash); + + // + result = TypeAsString() + "[" + Title() + "]" + mSep + hash; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + datetime mFrom; // Start Date + datetime mTo; // End Date + string mTitle; // Zone Title + + // +}; + +// +// Bar Zone ... +class XCBarZone : public XCZone +{ + // + public: + // + + // + // Constructor ... + void XCBarZone() + { + } + + // + // Deconstructor ... + void ~XCBarZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * @param upperPrice: ENUM_X_PRICE member ... + * @param lowerPrice: ENUM_X_PRICE member ... + * + * @return ( bool ) + */ + bool InitBarZone( + XOHCL &bar, + ENUM_XPOIS type, + ENUM_X_PRICE upperPrice, + ENUM_X_PRICE lowerPrice // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + type != X_POI_NONE && + upperPrice != lowerPrice; + if (!result) + { + return result; + } + + // + mBar = bar; + mType = type; + mUpperPrice = upperPrice; + mLowerPrice = lowerPrice; + mUpper = bar.GetPrice(upperPrice); + mLower = bar.GetPrice(lowerPrice); + + // + result = IsValidBarZone(); + if (result) + { + // + From(bar.time); + To(TimeCurrent()); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Fill Bar as XOHCL struct ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillBar( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + bar = mBar; + result = mBar.IsValid(); + + // + return result; + } + + /** + * Set From Date ... + * + * @param value: DateTime ... + */ + void From(datetime value) + { + // + if (!IsValidBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Set To Date ... + * + * @param value: DateTime ... + */ + void To(datetime value) + { + // + if (!IsValidBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Retrieve Bar Time ... + * + * @return ( datetime ) + */ + datetime BarTime() + { + return mBar.time; + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + if (!mBar.IsValid()) + { + return result; + } + + // + return mBar.symbol; + + // + return result; + } + + /** + * Get Period ... + * + * @return ( int ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + if (!mBar.IsValid()) + { + return result; + } + + // + return mBar.period; + + // + return result; + } + + /** + * Check Zone Started or not ... + * First Exit in Direction of Zone after From ... + * + * @param forDir: exit direction ... + * @param startedBar: specified Start Bar ... + * @param isBodyOut: specified Start Bar Close is Out of Zone or not ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsStarted( + ENUM_X_DIRECTION forDir, + XOHCL &startedBar, + bool &isBodyOut, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + startedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + // Detect From Bar Index ... + int fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + isBullish + ? isBreakedFromUpper + : isBreakedFromLower; + if (result) + { + // + startedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = startedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? startedBar.IsBullish() && + startedBar.GetUp() > Upper() + : startedBar.IsBearish() && + startedBar.GetDown() < Lower(); + } + + // + return result; + } + + /** + * Check Zone Activated or not ... + * First Enter in Opposit Direction of Zone after Start ... + * + * @param forDir: exit direction ... + * @param activatedBar: specified Activation Bar ... + * @param isBodyIn: specified Activation Bar Close is Inside of Zone or not ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsActivated( + ENUM_X_DIRECTION forDir, + XOHCL &activatedBar, + bool &isBodyIn, + bool forceBodyOutStarted = true, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyIn = false; + activatedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = IsStarted( + forDir, + startedBar, + isBodyOut, + forPeriod // + ); + result = + !forceBodyOutStarted + ? isStarted + : isStarted && + isBodyOut; + if (!result) + { + // + startedBar.Clean(); + return result; + } + + // + int fromIndex = startedBar.Index() - 1; + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isInsideFromUpper = + // + iBar.high < Upper() || + (iBar.high > Upper() && + iBar.low <= Upper() && + iBar.close <= Upper()) + // + ; + + // + bool isInsideFromLower = + // + iBar.low > Lower() || + (iBar.low < Lower() && + iBar.high >= Lower() && + iBar.close >= Lower()) + // + ; + + // + bool isInside = + isInsideFromUpper || + isInsideFromLower; + if (isInside) + { + // + result = isInside && + isBullish + ? isInsideFromUpper + : isInsideFromLower; + if (result) + { + // + activatedBar = iBar; + iBar.Clean(); + startedBar.Clean(); + break; + } + } + + // + iBar.Clean(); + startedBar.Clean(); + } + + // + result = activatedBar.IsValid(); + if (result) + { + // + isBodyIn = + isBullish + ? activatedBar.IsBearish() && + activatedBar.GetDown() < Upper() + : activatedBar.IsBullish() && + activatedBar.GetUp() > Lower(); + } + + // + return result; + } + + /** + * Check Zone Breaked or not ... + * + * @param forDir: exit direction ... + * @param breakedBar: specified Breaked Bar ... + * @param isBodyOut: specified Breaked Bar Close is Out of Zone or not ... + * @param ignoreStart: Ignore Zone Start (Calculate from From()) ... + * @param startedBodyOut: Started Bar Body Close State, if use Start for Calculation ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsBreaked( + ENUM_X_DIRECTION forDir, + XOHCL &breakedBar, + bool &isBodyOut, + bool ignoreStart = false, + bool startedBodyOut = false, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + breakedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + int fromIndex = -1; + if (!ignoreStart) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = IsStarted( + forDir, + startedBar, + isBodyOut, + forPeriod // + ); + + // + bool isStartPassed = + !startedBodyOut + ? isStarted + : isStarted && + isBodyOut; + if (isStartPassed) + { + fromIndex = startedBar.Index() - 1; + } + + // + startedBar.Clean(); + } + else + { + // + fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + } + + // + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + (isBullish + ? isBreakedFromLower + : isBreakedFromUpper); + if (result) + { + // + breakedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = breakedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? breakedBar.IsBearish() && + breakedBar.GetDown() < Lower() + : breakedBar.IsBullish() && + breakedBar.GetUp() > Upper(); + } + + // + return result; + } + + /** + * Check Zone Worked or not ... + * + * @param forDir: exit direction ... + * @param workedBar: specified Worked Bar ... + * @param isBodyOut: specified Worked Bar Close is Out of Zone or not ... + * @param ignoreActivation: Ignore Zone Activation (Calculate from From()) ... + * @param activationStartedOut: Specified Zone Start Bar State ... + * @param activationBodyIn: Specified Zone Activation Bar State ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsWorked( + ENUM_X_DIRECTION forDir, + XOHCL &workedBar, + bool &isBodyOut, + bool ignoreActivation = false, + bool activationStartedOut = false, + bool activationBodyIn = false, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + workedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + int fromIndex = -1; + if (!ignoreActivation) + { + // + XOHCL activatedBar; + bool isBodyIn = false; + bool isActivated = IsActivated( + forDir, + activatedBar, + isBodyIn, + activationStartedOut, + forPeriod // + ); + + // + bool isActivationPassed = + !activationBodyIn + ? isActivated + : isActivated && + isBodyIn; + if (isActivationPassed) + { + fromIndex = activatedBar.Index() - 1; + } + + // + activatedBar.Clean(); + } + else + { + // + fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + } + + // + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + isBullish + ? isBreakedFromUpper + : isBreakedFromLower; + if (result) + { + // + workedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = workedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? workedBar.IsBullish() && + workedBar.GetUp() > Upper() + : workedBar.IsBearish() && + workedBar.GetDown() < Lower(); + } + + // + return result; + } + + /** + * Check to Find Nearest Bar which Breakes Upper ... + * + * @param bar: XOHCL instance Reference, Breaker Bar ... + * @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ... + * + * @return ( bool ) + */ + bool FindNearestInsideBarFromUpper( + XOHCL &bar, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int from = 1; + int to = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = from; i < to; i++) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + if (!isInited) + { + break; + } + + // + bool isInside = iBar.low < Upper(); + if (isInside) + { + // + bar = iBar; + break; + } + } + + // + result = bar.IsValid(); + + // + return result; + } + + /** + * Check to Find Nearest Bar which Breakes Lower ... + * + * @param bar: XOHCL instance Reference, Breaker Bar ... + * @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ... + * + * @return ( bool ) + */ + bool FindNearestInsideBarFromLower( + XOHCL &bar, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int from = 1; + int to = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = from; i < to; i++) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + if (!isInited) + { + break; + } + + // + bool isInside = iBar.high > Lower(); + if (isInside) + { + // + bar = iBar; + break; + } + } + + // + result = bar.IsValid(); + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mBar.Clean(); + mUpper = 0; + mLower = 0; + mType = X_POI_NONE; + } + + datetime From() override + { + return mFrom; + } + + datetime To() override + { + return mTo; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValidBarZone()) + { + return result; + } + + // + string hash = ToMD5(mBar.GetTag()); + + // + result = + // + TypeAsString() + mSep + + ToString(mBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValidBarZone()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mBar; // Bar ... + ENUM_X_PRICE mUpperPrice; // Upper Price Selection + ENUM_X_PRICE mLowerPrice; // Lower Price Selection + + /** + * Check Bar Zone Validation ... + * + * @return ( bool ) + */ + bool IsValidBarZone() + { + // + bool result = false; + + // + result = mBar.IsValid() && + mType != X_POI_NONE && + IsValidBoundary(); + + // + return result; + } + + // + private: + // + // Props ... + datetime mFrom; + datetime mTo; + + // +}; +class XCTwoBarZone : public XCZone +{ + // + public: + // + + // + // Constructor ... + void XCTwoBarZone() + { + } + + // + // Deconstructor ... + void ~XCTwoBarZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * @param upperPrice: ENUM_X_PRICE member ... + * @param lowerPrice: ENUM_X_PRICE member ... + * + * @return ( bool ) + */ + bool InitTwoBarZone( + XOHCL &startBar, + XOHCL &endBar, + ENUM_XPOIS type, + ENUM_X_PRICE startPrice, + ENUM_X_PRICE endPrice // + ) + { + // + bool result = false; + + // + result = startBar.IsValid() && + endBar.IsValid() && + startBar.symbol == endBar.symbol && + startBar.period == endBar.period && + startBar.time < endBar.time && + type != X_POI_NONE; + if (!result) + { + return result; + } + + // + mType = type; + mEndBar = endBar; + mStartBar = startBar; + + // + int startIndex = startBar.Index(); + int endIndex = endBar.Index(); + + // + double mStartPrice = startBar.GetPrice(startPrice); + double mEndPrice = endBar.GetPrice(endPrice); + bool isStartOverEnd = mStartPrice > mEndPrice; + + // + if (isStartOverEnd) + { + // + mUpperPrice = startPrice; + mLowerPrice = endPrice; + } + else + { + // + mUpperPrice = endPrice; + mLowerPrice = startPrice; + } + + // + mUpper = MathMax(mStartPrice, mEndPrice); + mLower = MathMin(mStartPrice, mEndPrice); + + // + result = IsValidTwoBarZone(); + if (result) + { + // + From(startBar.time); + To(endBar.time); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set From Date ... + * + * @param value: DateTime ... + */ + void From(datetime value) + { + // + if (!IsValidTwoBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Set To Date ... + * + * @param value: DateTime ... + */ + void To(datetime value) + { + // + if (!IsValidTwoBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Fill Start Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillStartBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bar = mStartBar; + + // + return result; + } + + /** + * Fill End Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillEndBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bar = mEndBar; + + // + return result; + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + if (!mStartBar.IsValid()) + { + return result; + } + + // + return mStartBar.symbol; + + // + return result; + } + + /** + * Get Period ... + * + * @return ( int ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + if (!mStartBar.IsValid()) + { + return result; + } + + // + return mStartBar.period; + + // + return result; + } + + /** + * Check Zone Started or not ... + * First Exit in Direction of Zone after From ... + * + * @param forDir: exit direction ... + * @param startedBar: specified Start Bar ... + * @param isBodyOut: specified Start Bar Close is Out of Zone or not ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsStarted( + ENUM_X_DIRECTION forDir, + XOHCL &startedBar, + bool &isBodyOut, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + startedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + // Detect From Bar Index ... + int fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + isBullish + ? isBreakedFromUpper + : isBreakedFromLower; + if (result) + { + // + startedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = startedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? startedBar.IsBullish() && + startedBar.GetUp() > Upper() + : startedBar.IsBearish() && + startedBar.GetDown() < Lower(); + } + + // + return result; + } + + /** + * Check Zone Activated or not ... + * First Enter in Opposit Direction of Zone after Start ... + * + * @param forDir: exit direction ... + * @param activatedBar: specified Activation Bar ... + * @param isBodyIn: specified Activation Bar Close is Inside of Zone or not ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsActivated( + ENUM_X_DIRECTION forDir, + XOHCL &activatedBar, + bool &isBodyIn, + bool forceBodyOutStarted = true, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyIn = false; + activatedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = IsStarted( + forDir, + startedBar, + isBodyOut, + forPeriod // + ); + result = + !forceBodyOutStarted + ? isStarted + : isStarted && + isBodyOut; + if (!result) + { + // + startedBar.Clean(); + return result; + } + + // + int fromIndex = startedBar.Index() - 1; + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isInsideFromUpper = + // + iBar.high < Upper() || + (iBar.high > Upper() && + iBar.low <= Upper() && + iBar.close <= Upper()) + // + ; + + // + bool isInsideFromLower = + // + iBar.low > Lower() || + (iBar.low < Lower() && + iBar.high >= Lower() && + iBar.close >= Lower()) + // + ; + + // + bool isInside = + isInsideFromUpper || + isInsideFromLower; + if (isInside) + { + // + result = isInside && + isBullish + ? isInsideFromUpper + : isInsideFromLower; + if (result) + { + // + activatedBar = iBar; + iBar.Clean(); + startedBar.Clean(); + break; + } + } + + // + iBar.Clean(); + startedBar.Clean(); + } + + // + result = activatedBar.IsValid(); + if (result) + { + // + isBodyIn = + isBullish + ? activatedBar.IsBearish() && + activatedBar.GetDown() < Upper() + : activatedBar.IsBullish() && + activatedBar.GetUp() > Lower(); + } + + // + return result; + } + + /** + * Check Zone reaked or not ... + * + * @param forDir: exit direction ... + * @param breakedBar: specified Breaked Bar ... + * @param isBodyOut: specified Breaked Bar Close is Out of Zone or not ... + * @param ignoreStart: Ignore Zone Start (Calculate from From()) ... + * @param startedBodyOut: Started Bar Body Close State, if use Start for Calculation ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsBreaked( + ENUM_X_DIRECTION forDir, + XOHCL &breakedBar, + bool &isBodyOut, + bool ignoreStart = false, + bool startedBodyOut = false, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + breakedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + int fromIndex = -1; + if (!ignoreStart) + { + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = IsStarted( + forDir, + startedBar, + isBodyOut, + forPeriod // + ); + + // + bool isStartPassed = + !startedBodyOut + ? isStarted + : isStarted && + isBodyOut; + if (isStartPassed) + { + fromIndex = startedBar.Index() - 1; + } + + // + startedBar.Clean(); + } + else + { + // + fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + } + + // + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + (isBullish + ? isBreakedFromLower + : isBreakedFromUpper); + if (result) + { + // + breakedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = breakedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? breakedBar.IsBearish() && + breakedBar.GetDown() < Lower() + : breakedBar.IsBullish() && + breakedBar.GetUp() > Upper(); + } + + // + return result; + } + + /** + * Check Zone Worked or not ... + * + * @param forDir: exit direction ... + * @param workedBar: specified Worked Bar ... + * @param isBodyOut: specified Worked Bar Close is Out of Zone or not ... + * @param ignoreActivation: Ignore Zone Activation (Calculate from From()) ... + * @param activationStartedOut: Specified Zone Start Bar State ... + * @param activationBodyIn: Specified Zone Activation Bar State ... + * @param forPeriod: specified Period ... + * + * @return ( bool ) + */ + bool IsWorked( + ENUM_X_DIRECTION forDir, + XOHCL &workedBar, + bool &isBodyOut, + bool ignoreActivation = false, + bool activationStartedOut = false, + bool activationBodyIn = false, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + isBodyOut = false; + workedBar.Clean(); + + // + result = HasDirection(forDir) && + IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + int fromIndex = -1; + if (!ignoreActivation) + { + // + XOHCL activatedBar; + bool isBodyIn = false; + bool isActivated = IsActivated( + forDir, + activatedBar, + isBodyIn, + activationStartedOut, + forPeriod // + ); + + // + bool isActivationPassed = + !activationBodyIn + ? isActivated + : isActivated && + isBodyIn; + if (isActivationPassed) + { + fromIndex = activatedBar.Index() - 1; + } + + // + activatedBar.Clean(); + } + else + { + // + fromIndex = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + } + + // + result = IsValidIndex(fromIndex); + if (!result) + { + return result; + } + + // + for (int i = fromIndex; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + result = isInited; + if (!result) + { + // + iBar.Clean(); + continue; + } + + // + bool isBreakedFromUpper = + // + iBar.low > Upper() || + (iBar.low <= Upper() && + iBar.high > Upper() && + iBar.close > Upper()) + // + ; + + // + bool isBreakedFromLower = + // + iBar.low < Lower() || + (iBar.high >= Lower() && + iBar.low < Lower() && + iBar.close < Lower()) + // + ; + + // + bool isBreaked = + isBreakedFromUpper || + isBreakedFromLower; + if (isBreaked) + { + // + result = isBreaked && + isBullish + ? isBreakedFromUpper + : isBreakedFromLower; + if (result) + { + // + workedBar = iBar; + iBar.Clean(); + break; + } + } + + // + iBar.Clean(); + } + + // + result = workedBar.IsValid(); + if (result) + { + // + isBodyOut = + isBullish + ? workedBar.IsBullish() && + workedBar.GetUp() > Upper() + : workedBar.IsBearish() && + workedBar.GetDown() < Lower(); + } + + // + return result; + } + + /** + * Check to Find Nearest Bar which Breakes Upper ... + * + * @param bar: XOHCL instance Reference, Breaker Bar ... + * @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ... + * + * @return ( bool ) + */ + bool FindNearestInsideBarFromUpper( + XOHCL &bar, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int from = 1; + int to = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = from; i < to; i++) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + if (!isInited) + { + break; + } + + // + bool isInside = iBar.low < Upper(); + if (isInside) + { + // + bar = iBar; + break; + } + } + + // + result = bar.IsValid(); + + // + return result; + } + + /** + * Check to Find Nearest Bar which Breakes Lower ... + * + * @param bar: XOHCL instance Reference, Breaker Bar ... + * @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ... + * + * @return ( bool ) + */ + bool FindNearestInsideBarFromLower( + XOHCL &bar, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = GetPeriod(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int from = 1; + int to = iBarShift( + GetSymbol(), + forPeriod, + From() // + ); + + // + for (int i = from; i < to; i++) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + GetSymbol(), + forPeriod, + i // + ); + if (!isInited) + { + break; + } + + // + bool isInside = iBar.high > Lower(); + if (isInside) + { + // + bar = iBar; + break; + } + } + + // + result = bar.IsValid(); + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mStartBar.Clean(); + mEndBar.Clean(); + mUpper = 0; + mLower = 0; + mUseStartBarForUpper = false; + mType = X_POI_NONE; + } + + datetime From() override + { + return mFrom; + } + + datetime To() override + { + return mTo; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValidTwoBarZone()) + { + return result; + } + + // + string hash = ToMD5(mStartBar.GetTag() + mSep + mEndBar.GetTag()); + + // + result = + // + TypeAsString() + mSep + + ToString(mStartBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValidTwoBarZone()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mStartBar; // Start (Oldest) Bar ... + XOHCL mEndBar; // End (Newest) Bar ... + bool mUseStartBarForUpper; // Use Start Bar for Upper Calculation ... + ENUM_X_PRICE mUpperPrice; // Upper Price Selection + ENUM_X_PRICE mLowerPrice; // Lower Price Selection + + /** + * Check Two Bar Zone Validation ... + * + * @return ( bool ) + */ + bool IsValidTwoBarZone() + { + // + bool result = false; + + // + result = mStartBar.IsValid() && + mEndBar.IsValid() && + mStartBar.symbol == mEndBar.symbol && + mStartBar.period == mEndBar.period && + mStartBar.time < mEndBar.time && + mType != X_POI_NONE && + IsValidBoundary(); + + // + return result; + } + + // + private: + // + // Props ... + datetime mFrom; + datetime mTo; + + // +}; + +// +// Swing Class ... +class XCSwing : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCSwing() + { + } + + // + // Deconstructor ... + void ~XCSwing() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + ENUM_XPOIS type // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + (type == X_POI_SWING_HIGH || + type == X_POI_SWING_LOW); + if (!result) + { + return result; + } + + // + mBar = bar; + mType = type; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Fill Bar as XOHCL struct ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillBar( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + bar = mBar; + result = mBar.IsValid(); + + // + return result; + } + + /** + * Get Time of Swing ... + * + * @return ( datetime ) + */ + datetime GetTime() + { + // + datetime result = NULL; + + // + if (!IsValid() || !mBar.IsValid()) + { + return result; + } + + // + result = mBar.time; + + // + return result; + } + + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOHCL bar; + bool isFilled = FillBar(bar); + if (!isFilled) + { + return result; + } + + // + result = bar.period; + + // + return result; + } + + /** + * Check Swing High or not ... + * + * @return ( bool ) + */ + bool IsSwingHigh() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = + Type() == X_POI_SWING_HIGH; + + // + return result; + } + + /** + * Check Swing Low or not ... + * + * @return ( bool ) + */ + bool IsSwingLow() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = + Type() == X_POI_SWING_LOW; + + // + return result; + } + + /** + * Get Swing Value ... + * + * @return ( double ) + */ + double GetValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsSwingHigh() + ? mBar.high + : mBar.low; + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mBar.Clean(); + mType = X_POI_NONE; + } + + bool IsValid() override + { + // + bool result = false; + + // + result = mBar.IsValid() && + (mType == X_POI_SWING_HIGH || + mType == X_POI_SWING_LOW); + + // + return result; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = ToMD5(mBar.GetTag()); + + // + string subType = IsSwingHigh() + ? "High" + : "Low"; + + // + result = + // + TypeAsString() + mSep + + subType + mSep + + ToString(mBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mBar; // Swing Bar ... + + // + private: + // +}; + +// +// Supply Zone ... +class XCSupplyZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCSupplyZone() + { + } + + // + // Deconstructor ... + void ~XCSupplyZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0, + bool useRangeAsStart = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_SUPPLY_ZONE, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = + !useRangeAsStart + ? (datetime)((int)time - (range * periodSeconds)) + : time; + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_SUPPLY_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Demand Zone ... +class XCDemandZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCDemandZone() + { + } + + // + // Deconstructor ... + void ~XCDemandZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0, + bool useRangeAsStart = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_DEMAND_ZONE, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = + !useRangeAsStart + ? (datetime)((int)time - (range * periodSeconds)) + : time; + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_DEMAND_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Support Zone ... +class XCSupportZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCSupportZone() + { + } + + // + // Deconstructor ... + void ~XCSupportZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0, + bool useRangeAsStart = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_SUPPORT_ZONE, + X_PRICE_DOWN, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = + !useRangeAsStart + ? (datetime)((int)time - (range * periodSeconds)) + : time; + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_SUPPORT_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Resistance Zone ... +class XCResistanceZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCResistanceZone() + { + } + + // + // Deconstructor ... + void ~XCResistanceZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0, + bool useRangeAsStart = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_RESISTANCE_ZONE, + X_PRICE_HIGH, + X_PRICE_UP // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = + !useRangeAsStart + ? (datetime)((int)time - (range * periodSeconds)) + : time; + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_RESISTANCE_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Order Block ... +class XCOrderBlock : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCOrderBlock() + { + } + + // + // Deconstructor ... + void ~XCOrderBlock() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + ENUM_X_DIRECTION dir // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + (dir == X_DIRECTION_BULLISH || + dir == X_DIRECTION_BEARISH); + if (!result) + { + return result; + } + + // + ENUM_XPOIS mTT = + IsSpecifiedBullish(dir) + ? X_POI_BULLISH_ORDERBLOCK + : X_POI_BEARISH_ORDERBLOCK; + + // + result = InitBarZone( + bar, + mTT, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BULLISH_ORDERBLOCK; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BEARISH_ORDERBLOCK; + + // + return result; + } + + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + (mType == X_POI_BULLISH_ORDERBLOCK || + mType == X_POI_BEARISH_ORDERBLOCK); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Rejection Bar ... +class XCRejectionBar : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCRejectionBar() + { + } + + // + // Deconstructor ... + void ~XCRejectionBar() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = + bar.GetLowShadow() > bar.GetHighShadow(); + bool isBearish = + bar.GetHighShadow() > bar.GetLowShadow(); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + ENUM_X_PRICE upPrice = isBullish + ? X_PRICE_HIGH + : X_PRICE_DOWN; + // + ENUM_X_PRICE loPrice = isBullish + ? X_PRICE_UP + : X_PRICE_LOW; + + // + result = InitBarZone( + bar, + X_POI_REJECTION_BAR, + upPrice, + loPrice // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_REJECTION_BAR && + mBar.GetLowShadow() > mBar.GetHighShadow(); + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_REJECTION_BAR && + mBar.GetHighShadow() > mBar.GetLowShadow(); + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_REJECTION_BAR; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Momentum Bar ... +class XCMomentumBar : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCMomentumBar() + { + } + + // + // Deconstructor ... + void ~XCMomentumBar() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = bar.IsBullish(); + bool isBearish = bar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_MOMENTUM_BAR, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + mBar.IsBullish() && + Type() == X_POI_MOMENTUM_BAR; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + mBar.IsBearish() && + Type() == X_POI_MOMENTUM_BAR; + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_MOMENTUM_BAR; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Fair Value Gap ... +class XCFVG : public XCTwoBarZone +{ + // + public: + // + + // + // Constructor ... + void XCFVG() + { + } + + // + // Deconstructor ... + void ~XCFVG() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param startBar: XOHCL instance ... + * @param endBar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &startBar, + XOHCL &endBar, + ENUM_X_DIRECTION dir // + ) + { + // + bool result = false; + + // + result = endBar.IsValid() && + startBar.IsValid() && + (dir == X_DIRECTION_BULLISH || + dir == X_DIRECTION_BEARISH); + if (!result) + { + return result; + } + + // + bool isDirBullish = IsSpecifiedBullish(dir); + ENUM_XPOIS mTT = + isDirBullish + ? X_POI_BULLISH_FVG + : X_POI_BEARISH_FVG; + + // + ENUM_X_PRICE startPrice = isDirBullish + ? X_PRICE_HIGH + : X_PRICE_LOW; + ENUM_X_PRICE endPrice = isDirBullish + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + result = InitTwoBarZone( + startBar, + endBar, + mTT, + startPrice, + endPrice // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BULLISH_FVG; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BEARISH_FVG; + + // + return result; + } + + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidTwoBarZone() && + (mType == X_POI_BULLISH_FVG || + mType == X_POI_BEARISH_FVG); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Ticks Zones ... + +// +class XCTickZone : public CObject +{ + // + // Public ... + public: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + + // + double high; + double low; + int ticks; + double percent; + + // + ulong volume; + double volumePercent; + + // + // Compare Two Zone With Each Other ... + virtual int Compare( + const CObject *node, + const int mode = 0 // + ) const + { + // + const XCTickZone *other = (XCTickZone *)node; + + // + return other.ticks - ticks; + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = high > 0 && + low > 0 && + high > low && + ticks > 0 && + percent > 0; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // +}; + +// +class XCTicksZone : public XCTwoBarZone +{ + // + public: + // + + // + // Constructor ... + void XCTicksZone() + { + Default(); + } + + // + // Deconstructor ... + void ~XCTicksZone() + { + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Number of Ticks Levels ... + * + * @return ( int ) + */ + int Levels() + { + return mLevels; + } + + /** + * Set Number of Ticks Levels ... + * + * @return ( int ) + */ + void Levels(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mLevels = value; + } + + /** + * Apply Default Config ... + */ + virtual void Default() + { + // + Levels(10); + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param startBar: XOHCL instance ... + * @param endBar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &startBar, + XOHCL &endBar, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + result = endBar.IsValid() && + startBar.IsValid(); + if (!result) + { + return result; + } + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = endBar.period; + } + + // + // Calculate Start and End Time ... + datetime from = startBar.time; + datetime to = endBar.time; + ulong fromM = ((ulong)startBar.time * 1000); + ulong toM = ((ulong)endBar.time * 1000); + + // + // Symbol and Period ... + string symbol = startBar.symbol; + ENUM_TIMEFRAMES period = startBar.period; + + // + // Prepare Zones Array ... + mZones.Clear(); + + // + // Retrieve Ticks between Times ... + SpecificClean(mTicks); + CopyTicksRange( + symbol, + mTicks, + COPY_TICKS_ALL, + fromM, + toM // + ); + + // + // Ticks Volumes ... + int ticksVolumeCount = CopyTickVolume( + symbol, + forPeriod, + from, + to, + mTickVolumes // + ); + if (IsValidSize(ticksVolumeCount)) + { + // + mVolumes = 0; + for (int i = 0; i < ticksVolumeCount; i++) + { + mVolumes += mTickVolumes[i]; + } + } + + // + // Retrieve Highs ... + SpecificClean(mHighs); + CopyHigh( + symbol, + period, + from, + to, + mHighs // + ); + + // + // Retrieve Lows ... + SpecificClean(mLows); + CopyLow( + symbol, + period, + from, + to, + mLows // + ); + + // + // Find Highest Value in Range ... + int highIDX = ArrayMaximum(mHighs); + mRangeHigh = mHighs[highIDX]; + + // + // Find Lowest Value in Range ... + int lowIDX = ArrayMinimum(mLows); + mRangeLow = mLows[lowIDX]; + + // + datetime mTimes[]; + CopyTime( + symbol, + period, + from, + to, + mTimes // + ); + mRangeHighTime = mTimes[highIDX]; + mRangeLowTime = mTimes[lowIDX]; + + // + double mRangeSize = mRangeHigh - mRangeLow; + + // + // Create Zones ... + for (int i = 0; i < Levels(); i++) + { + // + // Instance a New Zone ... + XCTickZone *iZone = new XCTickZone(); + + // + iZone.symbol = symbol; + iZone.period = period; + + // + // Calculate Each Zones High / Low based on Range ... + double iH = mRangeHigh - mRangeSize * i / Levels(); + double iL = mRangeHigh - mRangeSize * (i + 1) / Levels(); + + // + // Set Zone High Low Properties ... + iZone.low = iL; + iZone.high = iH; + + // + // Add Zone to Zone Array Objects ... + mZones.Add(iZone); + } + + // + // Calculate Each Zone Ticks ... + int ticksCount = ArraySize(mTicks); + for (int i = 0; i < ticksCount; i++) + { + // + // Retrieve Tick ... + MqlTick iTick = mTicks[i]; + + // + // Loop through Zones ... + for (int j = 0; j < Levels(); j++) + { + // + // Rejrieve j indexed Zone Object ... + XCTickZone *jZone = mZones.At(j); + + // + bool isInRange = IsTickInZoneRange( + iTick, + jZone // + ); + if (isInRange) + { + // + jZone.ticks++; + break; + } + } + } + + // + // Calculating Zone Percents ... + for (int i = 0; i < Levels(); i++) + { + // + XCTickZone *iZone = mZones.At(i); + + // + double percent = CalculateZoneTickPercent(iZone); + iZone.percent = percent; + } + + // + // Sort Zones Based on Percents ... + mZones.Sort(); + + // + mUpper = mRangeHigh; + mLower = mRangeLow; + mType = X_POI_TICKS_ZONES; + mEndBar = endBar; + mStartBar = startBar; + From(startBar.time); + To(endBar.time); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + // Try to Find Out PERIOD_1M times in each zone ... + datetime to1M = (datetime)((int)endBar.time + PeriodSeconds(period) - 60); + int to1MIndex = iBarShift( + symbol, + forPeriod, + to1M // + ); + int from1MIndex = iBarShift( + symbol, + forPeriod, + from // + ); + for (int i = from1MIndex; i > to1MIndex; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + forPeriod, + i // + ); + if (!isInited) + { + continue; + } + ulong iVolume = iTickVolume( + symbol, + forPeriod, + i // + ); + + // + // Loop through Zones ... + for (int j = 0; j < Levels(); j++) + { + // + XCTickZone *jZone = mZones.At(j); + if (!jZone.IsValid()) + { + continue; + } + + // + // Check iBar is Inside jZone ... + bool isIBarInside = + iBar.GetUp() < jZone.high && + iBar.GetDown() > jZone.low; + // iBar.low < jZone.high || + // iBar.high > jZone.low; + if (isIBarInside) + { + jZone.volume += iVolume; + } + } + } + + // + // Calculate Volume Percent ... + for (int i = 0; i < Levels(); i++) + { + // + XCTickZone *iZone = mZones.At(i); + + // + if (mVolumes > 0) + { + iZone.volumePercent = (double)(iZone.volume * 100 / mVolumes); + } + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Retrieve Zones Count ... + * + * @return ( int ) + */ + int Count() + { + return mZones.Total(); + } + + /** + * Retrieve Specified Sorted Zones ... + * + * @param index: Integer ... + * + * @return ( XCTickZone * ) + */ + XCTickZone *GetZone(int index) + { + // + if (!IsValidIndex(index)) + { + return NULL; + } + + // + return mZones.At(index); + } + + /** + * Calculate Liquidity Percent for Specified Direction ... + * + * @param forDirection: ENUM_X_DIRECTION member, Specified Liquidity ... + * @param price: Double, Specified Price ... + * + * @return ( double ) + */ + double CalculateLiquidityPercent( + ENUM_X_DIRECTION forDirection, + double price // + ) + { + // + double result = 0; + + // + int count = Count(); + if (price <= 0 || + !IsValid() || + !IsValidSize(count) || + forDirection == X_DIRECTION_ALL || + forDirection == X_DIRECTION_NONE) + { + return result; + } + + // + bool isBullish = forDirection == X_DIRECTION_BULLISH; + + // + for (int i = 0; i < count; i++) + { + // + XCTickZone *iZone = GetZone(i); + + // + if (iZone.IsValid()) + { + // + result += !isBullish && + price > iZone.high + ? iZone.percent + : isBullish && + price < iZone.low + ? iZone.percent + : 0; + } + } + + // + return result; + } + + // + // Overrides ... + bool IsValid() override + { + // + bool result = false; + + // + result = + IsValidFrom() && + IsValidTwoBarZone() && + Levels() > 0 && + mZones.Total() == Levels() && + mRangeHigh > 0 && + mRangeLow > 0; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + + // + MqlTick mTicks[]; + double mHighs[]; + double mLows[]; + ulong mVolumes; + ulong mTickVolumes[]; + double mRangeHigh; + datetime mRangeHighTime; + double mRangeLow; + datetime mRangeLowTime; + + // + int mLevels; // Number of Ticks Levels ... + + // + CArrayObj mZones; + + /** + * Check a Tick is in a Zone rage or not ... + * + * @param tick: MqlTick instance ... + * @param zone: XCTickZone instance ... + * + * @return ( bool ) + */ + bool IsTickInZoneRange( + MqlTick &tick, + XCTickZone *zone // + ) + { + // + bool result = false; + + // + result = + // + tick.bid >= zone.low && + tick.bid <= zone.high + // + ; + + // + return result; + } + + /** + * Calculate Zone Tick Percent ... + * + * @param zone: XCTickZone instance ... + * @param normalizationDigits: Integer ... + * + * @return ( double ) + */ + double CalculateZoneTickPercent( + XCTickZone *zone, + int normalizationDigits = 2 // + ) + { + // + double result = 0; + + // + if (normalizationDigits < 2 || normalizationDigits > 5) + { + normalizationDigits = 2; + } + + // + int ticksCount = ArraySize(mTicks); + if (ticksCount <= 0) + { + return result; + } + + // + result = (double)zone.ticks / ticksCount * 100; + result = NormalizeDouble(result, normalizationDigits); + + // + return result; + } + + // +}; + +// +// Trading Day ... +class XCDay : public XCFromToZone +{ + // + public: + // + + // + // Constructor ... + void XCDay() + { + } + + // + // Deconstructor ... + void ~XCDay() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @return ( bool ) + */ + bool Init() + { + // + bool result = false; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + protected: + // + + // + private: + // + + // +}; + +// +// Trading Session ... +class XCSession : public XCFromToZone +{ + // + public: + // + + // + // Constructor ... + void XCSession() + { + } + + // + // Deconstructor ... + void ~XCSession() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @return ( bool ) + */ + bool Init() + { + // + bool result = false; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + protected: + // + + // + private: + // + + // +}; + +// +struct XBoxZone +{ + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + + // + double upper; + double lower; + + // + datetime from; + datetime to; + + // + string type; + ENUM_X_DIRECTION dir; + + // + // Constructor ... + XBoxZone() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + upper = 0; + lower = 0; + to = NULL; + from = NULL; + symbol = NULL; + period = NULL; + dir = X_DIRECTION_NONE; + + // + ZeroMemory(this); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + upper > 0 && + lower > 0 && + from < to && + IsValid(to) && + upper >= lower && + IsValid(from) && + IsValid(symbol) && + IsValid(period) + // + ; + + // + return result; + } + + bool IsBullish() + { + return IsValid() && + IsBullish(dir); + } + + bool IsBearish() + { + return IsValid() && + IsBearish(dir); + } + + bool IsSameAs(XBoxZone &item) + { + // + return IsValid() && + dir == item.dir && + from == item.from && + type == item.type && + lower == item.lower && + upper == item.upper && + symbol == item.symbol && + period == item.period; + } + + /** + * Check Box is Same as another ... + * + * @param box: XBoxZone instance Reference ... + * + * @return ( bool ) + */ + bool IsSame(XBoxZone &box) + { + // + bool result = false; + + // + result = IsValid() && + box.IsValid(); + if (!result) + { + return result; + } + + // + result = + // + dir == box.dir && + from == box.from && + type == box.type && + upper == box.upper && + lower == box.lower && + symbol == box.symbol && + period == box.period + // + ; + + // + return result; + } + + /** + * Retrieve Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = + // + "XBOX" + "_" + + ToString(dir) + "_" + + symbol + "_" + + ToString(period) + "_" + + ToString(upper) + "_" + + ToString(lower) + // + ; + + // + return result; + } +}; + +// diff --git a/BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.ex5 b/BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..83a5aa4deca843eacf667f5ed0ca01698c4616dc GIT binary patch literal 7804 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 z zi031{>V=@6CEP|?TWGa0s6~qtwNu+ zq0TGQUn=6#1elFFrgnHYV&{&#ROOjCjLS6tPQP7>= zT7su4weQk3*3lJq5HE>ba#7E^(B_6kEPhLH)g#!pD)s5=50yl4du_0MO<*vKn_2 zu$qF<3W**3#rOazm%kL(o_eLCE)O%n@-G|sQ=KsK8-s^a5}269m)+b8n@u45C?gkQ zY9?{X5%@I7+)ED-VJI`3BcVySFJ1j34Nqa*2gdkp7^W6j}e1wUXBY)Qwc{V7R$A(agL|uca+Q)8K+ZBGRCZALVAm`Ymlg8%&kfW zFKF58dFx!%*iH4CGw1l*Z@4~{<}#{Qsi7L>EU2j=t%Z>se8wgnyGVGbKl1998ZcTF07@kc@fkB%8hQITl4(OPqRx2>gvh-fbtT90qVkz4uB01g zM!QVY;+^otK@2fn3(6^QYG@tXY zV;7z}={c-?fsG~m4gF)At;{f(0@Ab$9e<{|(5Bm= zW{)_5QeG4~A55+QTs-gK**@cD=;D$~4)o2{Lz2cZuwH3nA zN+XZ3w~0X}85ls^i;OOuZ#UX6>Vvi>VchN})lV&rxI?>5PRB6)xIg+>|$>s17zL|QJX*EK%r5cca@%%qi^6}aL literal 0 HcmV?d00001 diff --git a/BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.mq5 b/BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.mq5 new file mode 100644 index 0000000..f50bc12 --- /dev/null +++ b/BKPS/14031218/Libraries/x-saherelm.x-poi.state.lib.mq5 @@ -0,0 +1,4523 @@ + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright `023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +enum ENUM_X_OBFVG_FVG_FILTERS +{ + X_OBFVG_FVG_FILTER_NONE, + X_OBFVG_FVG_FILTER_INSIDE_OR, + X_OBFVG_FVG_FILTER_ABOVE_BELOW, +}; + +// +enum ENUM_X_OBFVG_FVG_SELECTION +{ + X_OBFVG_FVG_SELECT_NONE, + X_OBFVG_FVG_SELECT_OLDEST, + X_OBFVG_FVG_SELECT_LOWEST, + X_OBFVG_FVG_SELECT_HIGHEST, + X_OBFVG_FVG_SELECT_YOUNGEST, + X_OBFVG_FVG_SELECT_HIGHEST_LOWEST, + X_OBFVG_FVG_SELECT_LOWEST_HIGHEST, +}; + +// +struct XOBFVGPivot +{ + // + // Props ... + double value; + datetime at; + + // + // Constructor ... + XOBFVGPivot() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + value = 0; + at = NULL; + + // + ZeroMemory(this); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + value > 0 && + IsValid(at); + + // + return result; + } +}; + +// +struct XOBFVG +{ + // + // Props ... + XCFVG *fvgs[]; + XCOrderBlock *ob; + + // + // Constructor ... + XOBFVG() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + Clean(fvgs); + ZeroMemory(ob); + + // + ZeroMemory(this); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = HasOB() && + HasFVGs(); + if (!result) + { + return result; + } + + // + XOHCL passedBar; + bool isBodyOut; + bool isOBStarted = ob.IsStarted( + ob.GetDirection(), + passedBar, + isBodyOut // + ); + + // + int idx = GetOldest(fvgs); + result = IsValidIndex(idx); + if (!result) + { + // + passedBar.Clean(); + return result; + } + + // + bool isFVGStarted = fvgs[idx].IsStarted( + ob.GetDirection(), + passedBar, + isBodyOut // + ); + + // + result = isOBStarted && + isFVGStarted; + + // + passedBar.Clean(); + + // + return result; + } + + // + bool HasOB() + { + return ob != NULL && + ob.IsValid(); + } + + // + bool HasFVGs() + { + return HasChild(fvgs); + } + + // + int CountFVGs() + { + return ArraySize(fvgs); + } + + // + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + bool isValid = IsValid(); + if (!isValid) + { + return result; + } + + // + result = ob.GetDirection(); + + // + return result; + } + + // + bool IsBullish() + { + return IsBullish(GetDirection()); + } + + // + bool IsBearish() + { + return IsBearish(GetDirection()); + } + + // + int GetSwings( + XOBFVGPivot &pivots[] // + ) + { + // + int result = 0; + + // + Clean(pivots); + + // + if (!IsValid()) + { + return result; + } + + // + ENUM_X_DIRECTION forDir = GetDirection(); + bool isBullish = IsBullish(forDir); + + // + XOHCL passedBar; + XOBFVGPivot iPivot; + bool isPassed = false; + double appliedPrice = 0; + bool isBodyState = false; + + // + // Start ... + isPassed = ob.IsStarted( + forDir, + passedBar, + isBodyState // + ); + if (isPassed) + { + // + appliedPrice = + isBullish + ? passedBar.low + : passedBar.high; + + // + iPivot.Clean(); + iPivot.value = appliedPrice; + iPivot.at = passedBar.time; + + // + AddRef( + iPivot, + pivots // + ); + + // + iPivot.Clean(); + } + + // + // Activation ... + isPassed = ob.IsActivated( + forDir, + passedBar, + isBodyState // + ); + if (isPassed) + { + // + appliedPrice = + isBullish + ? passedBar.low + : passedBar.high; + + // + iPivot.Clean(); + iPivot.value = appliedPrice; + iPivot.at = passedBar.time; + + // + AddRef( + iPivot, + pivots // + ); + + // + iPivot.Clean(); + } + + // + // Worked ... + isPassed = ob.IsWorked( + forDir, + passedBar, + isBodyState // + ); + if (isPassed) + { + // + appliedPrice = + isBullish + ? passedBar.low + : passedBar.high; + + // + iPivot.Clean(); + iPivot.value = appliedPrice; + iPivot.at = passedBar.time; + + // + AddRef( + iPivot, + pivots // + ); + + // + iPivot.Clean(); + } + + // + passedBar.Clean(); + + // + result = ArraySize(pivots); + + // + return result; + } + + // + bool GetMainFVG( + XCFVG *&fvg // + ) + { + // + bool result = false; + + // + fvg = NULL; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = GetOldest(fvgs); + result = IsValidIndex(idx); + if (!result) + { + // + ZeroMemory(fvg); + return result; + } + + // + fvg = fvgs[idx]; + result = fvg != NULL && + fvg.IsValid(); + + // + return result; + } + + // + bool IsValidZone( + int barIndex = 0 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XCFVG *tmpFVGs[]; + Copy( + fvgs, + tmpFVGs // + ); + int count = CountFVGs(); + for (int i = 0; i < count; i++) + { + // + XCFVG *iFVG = tmpFVGs[i]; + + // + XOHCL startedBar; + bool isBodyOut = false; + result = iFVG.IsStarted( + iFVG.GetDirection(), + startedBar, + isBodyOut // + ); + if (!result) + { + // + ZeroMemory(iFVG); + startedBar.Clean(); + ArrayRemove( + fvgs, + i, + 1 // + ); + + // + continue; + } + + // + XOHCL bar; + bool isBullish = iFVG.IsBullish(); + datetime fromTime = startedBar.NextAt(); + + // + int fromIndex = iBarShift( + iFVG.GetSymbol(), + iFVG.GetPeriod(), + fromTime // + ); + result = IsValidIndex(fromIndex); + if (!result) + { + // + bar.Clean(); + ZeroMemory(iFVG); + startedBar.Clean(); + ArrayRemove( + fvgs, + i, + 1 // + ); + + // + continue; + } + + // + bool isInited = false; + bool isValidFVG = false; + for (int j = barIndex; j < fromIndex; j++) + { + // + isInited = bar.Init( + iFVG.GetSymbol(), + iFVG.GetPeriod(), + j // + ); + if (!isInited) + { + // + bar.Clean(); + continue; + } + + // + // bool isBarAbove = + // bar.low > iFVG.Upper(); + // bool isBarBelow = + // bar.high < iFVG.Lower(); + + // + bool isBarAbove = + bar.GetDown() > iFVG.Upper(); + bool isBarBelow = + bar.GetUp() < iFVG.Lower(); + + // + isValidFVG = + isBullish + ? isBarAbove + : isBarBelow; + if (!isValidFVG) + { + // + bar.Clean(); + + // + break; + } + + // + bar.Clean(); + } + + // + if (!isValidFVG) + { + // + ArrayRemove( + fvgs, + i, + 1 // + ); + } + + // + bar.Clean(); + ZeroMemory(iFVG); + startedBar.Clean(); + } + + // + Clean(tmpFVGs); + + // + result = HasFVGs(); + + // + return result; + } + + // + bool ToZone(XBoxZone &box) + { + // + bool result = false; + + // + result = ToZoneBox( + box, + this // + ); + + // + return result; + } + + // + void AddFVG(XCFVG *fvg) + { + // + int idx = -1; + bool has = false; + + // + has = + HasOB() && + fvg != NULL && + fvg.IsValid() && + ob.GetDirection() == fvg.GetDirection(); + if (!has) + { + return; + } + + // + idx = FindIndex( + fvg, + fvgs // + ); + has = !IsValidIndex(idx); + if (!has) + { + return; + } + + // + Add( + fvg, + fvgs // + ); + } + + // + bool IsSameAs(XOBFVG &item) + { + // + bool result = false; + + // + result = IsValid() && + IsSame(ob, item.ob); + + // + return result; + } + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasOB(); + if (has) + { + ob.To(value); + } + + // + has = HasFVGs(); + if (has) + { + // + count = CountFVGs(); + for (int i = 0; i < count; i++) + { + fvgs[i].To(value); + } + } + } +}; + +// +// +// Model Exists Founded POIs ... +struct XPOIState +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + XCSwing *swings[]; // Holds Founded Swing ... + XCSwing *swingLows[]; // Holds Founded Swing Lows ... + XCSwing *swingHighs[]; // Holds Founded Swing Highs ... + + // + XCMomentumBar *momentumBars[]; // Holds Founded Momentum Bars ... + XCMomentumBar *bullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ... + XCMomentumBar *bearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ... + + // + XCRejectionBar *rejectionBars[]; // Holds Founded Rejection Bars ... + XCRejectionBar *bullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ... + XCRejectionBar *bearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ... + + // + XCSupportZone *supportZones[]; // Holds Founded Support Zones ... + XCResistanceZone *resistanceZones[]; // Holds Founded Resistance Zones ... + + // + XCSupplyZone *supplyZones[]; // Holds Founded Supply Zones ... + XCDemandZone *demandZones[]; // Holds Founded Demand Zones ... + + // + XCOrderBlock *orderBlocks[]; // Holds Founded Order Blocks ... + XCOrderBlock *bullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ... + XCOrderBlock *bearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ... + + // + XCFVG *fairValueGaps[]; // Holds Founded Fair Value Gaps ... + XCFVG *bullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ... + XCFVG *bearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ... + + // + XConsolidationZone consolidationZones[]; // Holds Founded Consolidation Zones ... + XConsolidationZone bullishConsolidationZones[]; // Holds Founded Bullish Consolidation Zones ... + XConsolidationZone bearishConsolidationZones[]; // Holds Founded Bearih Consolidation Zones ... + + // + // Constructor ... + void XPOIState() + { + Clean(); + } + + // + // Actions ... + + /** + * Cleanup all props ... + */ + void Clean() + { + // + time = NULL; + symbol = NULL; + period = NULL; + + // + Clean(swings); + Clean(swingLows); + Clean(swingHighs); + + // + Clean(momentumBars); + Clean(bullishMomentumBars); + Clean(bearishMomentumBars); + + // + Clean(rejectionBars); + Clean(bullishRejectionBars); + Clean(bearishRejectionBars); + + // + Clean(supportZones); + Clean(resistanceZones); + + // + Clean(supplyZones); + Clean(demandZones); + + // + Clean(orderBlocks); + Clean(bullishOrderBlocks); + Clean(bearishOrderBlocks); + + // + Clean(fairValueGaps); + Clean(bullishFairValueGaps); + Clean(bearishFairValueGaps); + + // + Clean(consolidationZones); + Clean(bullishConsolidationZones); + Clean(bearishConsolidationZones); + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + + // + return result; + } + + /** + * Check State has Childs or not ... + * + * @return ( bool ) + */ + bool HasChild() + { + // + bool result = false; + + // + result = + // + HasSwingLows() || + HasSwingHighs() || + HasSupplyZones() || + HasDemandZones() || + HasSupportZones() || + HasResistanceZones() || + HasBullishOrderBlocks() || + HasBearishOrderBlocks() || + HasBullishMomentumBars() || + HasBearishMomentumBars() || + HasBullishRejectionBars() || + HasBearishRejectionBars() || + HasBullishFairValueGaps() || + HasBearishFairValueGaps() || + HasBullishConsolidationZones() || + HasBearishConsolidationZones() + // + ; + + // + return result; + } + + // + // Counters ... + + // + int CountSwings() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(swings); + + // + return result; + } + + // + bool HasSwings() + { + return IsValidSize(CountSwings()); + } + + // + int CountSwingHighs() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(swingHighs); + + // + return result; + } + + // + bool HasSwingHighs() + { + return IsValidSize(CountSwingHighs()); + } + + // + int CountSwingLows() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(swingLows); + + // + return result; + } + + // + bool HasSwingLows() + { + return IsValidSize(CountSwingLows()); + } + + // + int CountMomentumBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(momentumBars); + + // + return result; + } + + // + bool HasMomentumBars() + { + return IsValidSize(CountMomentumBars()); + } + + // + int CountBullishMomentumBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishMomentumBars); + + // + return result; + } + + // + bool HasBullishMomentumBars() + { + return IsValidSize(CountBullishMomentumBars()); + } + + // + int CountBearishMomentumBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishMomentumBars); + + // + return result; + } + + // + bool HasBearishMomentumBars() + { + return IsValidSize(CountBearishMomentumBars()); + } + + // + int CountRejectionBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(rejectionBars); + + // + return result; + } + + // + bool HasRejectionBars() + { + return IsValidSize(CountRejectionBars()); + } + + // + int CountBullishRejectionBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishRejectionBars); + + // + return result; + } + + // + bool HasBullishRejectionBars() + { + return IsValidSize(CountBullishRejectionBars()); + } + + // + int CountBearishRejectionBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishRejectionBars); + + // + return result; + } + + // + bool HasBearishRejectionBars() + { + return IsValidSize(CountBearishRejectionBars()); + } + + // + int CountSupportZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(supportZones); + + // + return result; + } + + // + bool HasSupportZones() + { + return IsValidSize(CountSupportZones()); + } + + // + int CountResistanceZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(resistanceZones); + + // + return result; + } + + // + bool HasResistanceZones() + { + return IsValidSize(CountResistanceZones()); + } + + // + int CountSupplyZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(supplyZones); + + // + return result; + } + + // + bool HasSupplyZones() + { + return IsValidSize(CountSupplyZones()); + } + + // + int CountDemandZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(demandZones); + + // + return result; + } + + // + bool HasDemandZones() + { + return IsValidSize(CountDemandZones()); + } + + // + int CountOrderBlocks() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(orderBlocks); + + // + return result; + } + + // + bool HasOrderBlocks() + { + return IsValidSize(CountOrderBlocks()); + } + + // + int CountBullishOrderBlocks() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishOrderBlocks); + + // + return result; + } + + // + bool HasBullishOrderBlocks() + { + return IsValidSize(CountBullishOrderBlocks()); + } + + // + int CountBearishOrderBlocks() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishOrderBlocks); + + // + return result; + } + + // + bool HasBearishOrderBlocks() + { + return IsValidSize(CountBearishOrderBlocks()); + } + + // + int CountFairValueGaps() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(fairValueGaps); + + // + return result; + } + + // + bool HasFairValueGaps() + { + return IsValidSize(CountFairValueGaps()); + } + + // + int CountBullishFairValueGaps() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishFairValueGaps); + + // + return result; + } + + // + bool HasBullishFairValueGaps() + { + return IsValidSize(CountBullishFairValueGaps()); + } + + // + int CountBearishFairValueGaps() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishFairValueGaps); + + // + return result; + } + + // + bool HasBearishFairValueGaps() + { + return IsValidSize(CountBearishFairValueGaps()); + } + + // + bool HasConsolidationZones() + { + return HasChild(consolidationZones); + } + + // + int CountConsolidationZones() + { + return ArraySize(consolidationZones); + } + + // + bool HasBullishConsolidationZones() + { + return HasChild(bullishConsolidationZones); + } + + // + int CountBullishConsolidationZones() + { + return ArraySize(bullishConsolidationZones); + } + + // + bool HasBearishConsolidationZones() + { + return HasChild(bearishConsolidationZones); + } + + // + int CountBearishConsolidationZones() + { + return ArraySize(bearishConsolidationZones); + } + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasMomentumBars(); + if (has) + { + // + count = CountMomentumBars(); + for (int i = 0; i < count; i++) + { + momentumBars[i].To(value); + } + } + + // + has = HasBullishMomentumBars(); + if (has) + { + // + count = CountBullishMomentumBars(); + for (int i = 0; i < count; i++) + { + bullishMomentumBars[i].To(value); + } + } + + // + has = HasBearishMomentumBars(); + if (has) + { + // + count = CountBearishMomentumBars(); + for (int i = 0; i < count; i++) + { + bearishMomentumBars[i].To(value); + } + } + + // + has = HasRejectionBars(); + if (has) + { + // + count = CountRejectionBars(); + for (int i = 0; i < count; i++) + { + rejectionBars[i].To(value); + } + } + + // + has = HasBullishRejectionBars(); + if (has) + { + // + count = CountBullishRejectionBars(); + for (int i = 0; i < count; i++) + { + bullishRejectionBars[i].To(value); + } + } + + // + has = HasBearishRejectionBars(); + if (has) + { + // + count = CountBearishRejectionBars(); + for (int i = 0; i < count; i++) + { + bearishRejectionBars[i].To(value); + } + } + + // + has = HasSupportZones(); + if (has) + { + // + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + supportZones[i].To(value); + } + } + + // + has = HasResistanceZones(); + if (has) + { + // + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + resistanceZones[i].To(value); + } + } + + // + has = HasSupplyZones(); + if (has) + { + // + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + supplyZones[i].To(value); + } + } + + // + has = HasDemandZones(); + if (has) + { + // + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + demandZones[i].To(value); + } + } + + // + has = HasOrderBlocks(); + if (has) + { + // + count = CountOrderBlocks(); + for (int i = 0; i < count; i++) + { + orderBlocks[i].To(value); + } + } + + // + has = HasBullishOrderBlocks(); + if (has) + { + // + count = CountBullishOrderBlocks(); + for (int i = 0; i < count; i++) + { + bullishOrderBlocks[i].To(value); + } + } + + // + has = HasBearishOrderBlocks(); + if (has) + { + // + count = CountBearishOrderBlocks(); + for (int i = 0; i < count; i++) + { + bearishOrderBlocks[i].To(value); + } + } + + // + has = HasFairValueGaps(); + if (has) + { + // + count = CountFairValueGaps(); + for (int i = 0; i < count; i++) + { + fairValueGaps[i].To(value); + } + } + + // + has = HasBullishFairValueGaps(); + if (has) + { + // + count = CountBullishFairValueGaps(); + for (int i = 0; i < count; i++) + { + bullishFairValueGaps[i].To(value); + } + } + + // + has = HasBearishFairValueGaps(); + if (has) + { + // + count = CountBearishFairValueGaps(); + for (int i = 0; i < count; i++) + { + bearishFairValueGaps[i].To(value); + } + } + } + + // + // Filter Zones ... + + // + // Support ... + int FilterSupportZones( + XCSupportZone *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasSupportZones(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BULLISH; + count = CountSupportZones(); + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = supportZones[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Resistance ... + int FilterResistanceZones( + XCResistanceZone *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasResistanceZones(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BEARISH; + count = CountResistanceZones(); + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = resistanceZones[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Supply ... + int FilterSupplyZones( + XCSupplyZone *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasSupplyZones(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BEARISH; + count = CountSupplyZones(); + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = supplyZones[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Demand ... + int FilterDemandZones( + XCDemandZone *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasDemandZones(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BULLISH; + count = CountDemandZones(); + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = demandZones[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // OrderBlock ... + int FilterOrderBlocks( + XCOrderBlock *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasOrderBlocks(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + count = CountOrderBlocks(); + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = orderBlocks[i]; + passedDir = iZone.GetDirection(); + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Bullish OrderBlock ... + int FilterBullishOrderBlocks( + XCOrderBlock *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasBullishOrderBlocks(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BULLISH; + count = CountBullishOrderBlocks(); + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = bullishOrderBlocks[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Bearish OrderBlock ... + int FilterBearishOrderBlocks( + XCOrderBlock *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasBearishOrderBlocks(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BEARISH; + count = CountBearishOrderBlocks(); + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = bearishOrderBlocks[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // FairValueGap ... + int FilterFairValueGaps( + XCFVG *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasFairValueGaps(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + count = CountFairValueGaps(); + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = fairValueGaps[i]; + passedDir = iZone.GetDirection(); + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Bullish FairValueGap ... + int FilterBullishFairValueGaps( + XCFVG *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasBullishFairValueGaps(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BULLISH; + count = CountBullishFairValueGaps(); + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = bullishFairValueGaps[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Bearish FairValueGap ... + int FilterBearishFairValueGaps( + XCFVG *&dest[], + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int result = 0; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + Clean(dest); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasBearishFairValueGaps(); + if (!has) + { + return result; + } + + // + XOHCL passedBar; + ENUM_X_DIRECTION passedDir = X_DIRECTION_NONE; + passedDir = X_DIRECTION_BEARISH; + count = CountBearishFairValueGaps(); + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = bearishFairValueGaps[i]; + + // + // Check Started State ... + if (startState == XZONE_STATE_PASSED || + startState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isStarted = iZone.IsStarted( + passedDir, + passedBar, + isBodyOut, + forPeriod // + ); + + // + bool isPassed = + startState == XZONE_STATE_FAILED + ? !isStarted + : !forceStartedBodyOut + ? isStarted + : isStarted && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Activation State ... + if (activeState == XZONE_STATE_PASSED || + activeState == XZONE_STATE_FAILED) + { + // + bool isBodyIn = false; + bool isActivated = iZone.IsActivated( + passedDir, + passedBar, + isBodyIn, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + activeState == XZONE_STATE_FAILED + ? !isActivated + : !forceActivatedBodyIn + ? isActivated + : isActivated && + isBodyIn; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Break State ... + if (breakState == XZONE_STATE_PASSED || + breakState == XZONE_STATE_FAILED) + { + // + bool isBodyOut = false; + bool isBreaked = iZone.IsBreaked( + passedDir, + passedBar, + isBodyOut, + forceStartedBodyOut, + forPeriod // + ); + + // + bool isPassed = + breakState == XZONE_STATE_FAILED + ? !isBreaked + : !forceBreakedBodyOut + ? isBreaked + : isBreaked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Work State ... + if (workState == XZONE_STATE_PASSED || + workState == XZONE_STATE_FAILED) + { + // + bool ignoreActivation = activeState != XZONE_STATE_PASSED; + + // + bool isBodyOut = false; + bool isWorked = iZone.IsWorked( + passedDir, + passedBar, + isBodyOut, + ignoreActivation, + forceStartedBodyOut, + forceActivatedBodyIn, + forPeriod // + ); + + // + bool isPassed = + workState == XZONE_STATE_FAILED + ? !isWorked + : !forceWorkedBodyOut + ? isWorked + : isWorked && + isBodyOut; + + // + passedBar.Clean(); + if (!isPassed) + { + continue; + } + } + + // + // Check Filtered Zone Doesn't Exists ... + has = FindIndex( + idx, + iZone, + dest // + ); + if (has) + { + // + passedBar.Clean(); + continue; + } + + // + Add( + iZone, + dest // + ); + + // + // End For ... + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + void Filter( + XPOIState &dest, + ENUM_TIMEFRAMES forPeriod = NULL, + // + // Start ... + ENUM_XZONE_STATE startState = XZONE_STATE_PASSED, + bool forceStartedBodyOut = false, + // + // Activation ... + ENUM_XZONE_STATE activeState = XZONE_STATE_FAILED, + bool forceActivatedBodyIn = false, + // + // Breaktion ... + ENUM_XZONE_STATE breakState = XZONE_STATE_FAILED, + bool forceBreakedBodyOut = false, + // + // Works ... + ENUM_XZONE_STATE workState = XZONE_STATE_FAILED, + bool forceWorkedBodyOut = false // + ) + { + // + int count = 0; + bool has = false; + + // + dest.Clean(); + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + has = IsValid() && + HasChild(); + if (!has) + { + return; + } + + // + dest = this; + + // + // Support Zones ... + FilterSupportZones( + dest.supportZones, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Resistance Zones ... + FilterResistanceZones( + dest.resistanceZones, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Supply Zones ... + FilterSupplyZones( + dest.supplyZones, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Demand Zones ... + FilterDemandZones( + dest.demandZones, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // OrderBlocks ... + FilterOrderBlocks( + dest.orderBlocks, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Bullish OrderBlocks ... + FilterBullishOrderBlocks( + dest.bullishOrderBlocks, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Bearish OrderBlocks ... + FilterBearishOrderBlocks( + dest.bearishOrderBlocks, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // FairValueGaps ... + FilterFairValueGaps( + dest.fairValueGaps, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Bullish FairValueGaps ... + FilterBullishFairValueGaps( + dest.bullishFairValueGaps, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + // Bearish FairValueGaps ... + FilterBearishFairValueGaps( + dest.bearishFairValueGaps, + forPeriod, + startState, + forceStartedBodyOut, + activeState, + forceActivatedBodyIn, + breakState, + forceBreakedBodyOut, + workState, + forceWorkedBodyOut // + ); + + // + } + + // +}; + +// +// Extensions Functions ... +// + +/** + * Update to Time of Specifiex Collection ... + * + * @param items: XOBFVG instance Collection ... + * @param value: datetime ... + */ +void SpecifiedUpdateTo( + XOBFVG &items[], + datetime value = NULL // +) +{ + // + value = NormalizeTime(value); + + // + int count = ArraySize(items); + bool has = HasChild(items); + if (!has) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + items[i].UpdateTo(value); + } +} + +/** + * Extract Box Zone's of Specified OBFVG ... + * + * @param box: XBoxZone instance, represent result ... + * @param obfvg: XOBFVG instance, specified Model ... + * + * @return ( bool ) + */ +bool ToZoneBox( + XBoxZone &box, + XOBFVG &obfvg // +) +{ + // + bool result = false; + + // + box.Clean(); + + // + // Check Model Validation ... + result = obfvg.IsValid(); + if (!result) + { + return result; + } + + // + // Retrieve Model Main Fair Value Gap ... + XCFVG *fvg; + result = obfvg.GetMainFVG(fvg); + if (!result) + { + // + box.Clean(); + ZeroMemory(fvg); + + // + return result; + } + + // + bool isBullish = fvg.IsBullish(); + + // + // Retrieve Main Fair Value Gap's Started Bar ... + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = fvg.IsStarted( + fvg.GetDirection(), + startedBar, + isBodyOut // + ); + result = isStarted; + if (!result) + { + // + box.Clean(); + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; + } + + // + // Converts Main Fair Value Gaps to Box ... + result = ToBox( + box, + fvg // + ); + if (!result) + { + // + box.Clean(); + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; + } + + // + // Validate Start Bar ... + result = + isBullish + ? startedBar.high >= fvg.Upper() && + startedBar.low < fvg.Upper() + : startedBar.low <= fvg.Lower() && + startedBar.high > fvg.Lower(); + if (!result) + { + // + box.Clean(); + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; + } + + // + // Update Box using Started Bar ... + box.lower = isBullish + ? box.lower + : startedBar.low; + box.upper = + isBullish + ? startedBar.high + : box.upper; + + // + box.from = startedBar.NextAt(); + + // + // Check Box Validation ... + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + // Cleanup Resources ... + ZeroMemory(fvg); + startedBar.Clean(); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &box, + XOBFVG &item // +) +{ + // + bool result = false; + + // + result = ToBox( + box, + item.ob // + ); + + // + return result; +} + +/** + * Converts to XBoxZone ... + * + * @return ( bool ) + */ +int ToBox( + XOBFVG &source[], + XBoxZone &dest[] // +) +{ + // + int result = 0; + + // + Clean(dest); + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XOBFVG iZone = source[i]; + + // + XBoxZone iBox; + bool hasBox = ToBox( + iBox, + iZone // + ); + + // + if (hasBox) + { + // + AddRef( + iBox, + dest // + ); + } + + // + iBox.Clean(); + iZone.Clean(); + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// +// + +/** + * Get Oldest Index ... + * + * @param source: XOBFVG instance Reference Collection ... + * + * @return ( int ) + */ +int GetOldest( + XOBFVG &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from > iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index ... + * + * @param source: XOBFVG instance Reference Collection ... + * + * @return ( int ) + */ +int GetYoungest( + XOBFVG &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from < iBox.from; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Index ... + * + * @param source: XOBFVG instance Reference Collection ... + * + * @return ( int ) + */ +int GetHighest( + XOBFVG &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.upper < iBox.upper; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Index ... + * + * @param source: XOBFVG instance Reference Collection ... + * + * @return ( int ) + */ +int GetLowest( + XOBFVG &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone tmpBoxes[]; + int boxesCount = ToBox( + source, + tmpBoxes // + ); + if (!IsValidSize(boxesCount)) + { + // + Clean(tmpBoxes); + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < boxesCount; i++) + { + // + XBoxZone iBox = tmpBoxes[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.lower > iBox.lower; + if (canSet) + { + // + result = i; + selected = iBox; + } + } + + // + Clean(tmpBoxes); + selected.Clean(); + + // + return result; +} + +bool AddIfNotExists( + XOBFVG &item, + XOBFVG &items[] // +) +{ + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + int before = ArraySize(items); + + // + int idx = FindIndex( + item, + items // + ); + bool has = IsValidIndex(idx); + result = !has; + if (!result) + { + return result; + } + + // + AddRef( + item, + items // + ); + + // + int after = ArraySize(items); + + // + result = after > before; + + // + return result; +} + +int AddIfNotExists( + XOBFVG &items[], + XOBFVG &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items); + if (!has) + { + return result; + } + + // + int before = ArraySize(sources); + + // + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + has = AddIfNotExists( + items[i], + sources // + ); + } + + // + int after = ArraySize(sources); + + // + result = after > before; + + // + return result; +} + +// diff --git a/BKPS/14031218/Libraries/x-saherelm.x-trade.lib.ex5 b/BKPS/14031218/Libraries/x-saherelm.x-trade.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..3cb7ff3fa22b03af4980b9f2b50cbb09c8d9dc3c GIT binary patch literal 11796 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 + +// +// Definitions ... + +// +// a List of Used Tokens ... + +// +// Common ... +string XIDToken = "ID"; +string XTicketToken = "TK"; +string XModeToken = "MD"; +string XTypeToken = "TY"; +string XPeriodToken = "PR"; +string XProviderToken = "PRV"; +string XProfitToken = "PF"; + +// +string XTPToken = "TP"; +string XSLToken = "SL"; +string XTimeToken = "TM"; +string XEntryToken = "EN"; +string XVolumeToken = "VL"; +string XSymbolToken = "SMBL"; + +// +string XSupportToken = "SP"; +string XEQMSupportToken = "EQM"; +string XEQPToken = "EQP"; + +// +string XSLTrailToken = "SLT"; + +// +string XActionToken = "A"; + +// +string XDirectionalToken = "D"; +string XINDirectionalToken = "IND"; + +// +string XRecoveryToken = "XRCV"; + +// +// Available Order Modes ... +enum ENUM_X_ORDER_MODES +{ + X_ORDER_MODE_NOTHING, // Nothing + X_ORDER_MODE_MARKET, // Market Order + X_ORDER_MODE_STOP, // Pending Stop Order + X_ORDER_MODE_LIMIT, // Pending Limit Order + X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order +}; + +// +string ToString(ENUM_X_ORDER_MODES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_ORDER_MODE_MARKET: + result = "Market"; + break; + + // + case X_ORDER_MODE_LIMIT: + result = "Limit"; + break; + + // + case X_ORDER_MODE_STOP: + result = "Stop"; + break; + + // + case X_ORDER_MODE_STOP_LIMIT: + result = "StopLimit"; + break; + } + + // + return result; +} + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_BOTH, // Min and Max + X_POSITION_SELECT_ALL, // All +}; + +// +// Signal Execution Result ... +// note that some of them must be handles in +// EA's ... +enum ENUM_X_SIGNAL_EXECUTION_RESULT +{ + // + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed + X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR, // Prev Profit Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params +}; + +// +// Available Guard Action ... +enum ENUM_X_GUARD_ACTIONS +{ + X_GUARD_ACTION_NOTHING, // Nothing + X_GUARD_ACTION_HEDGE, // Hedge + X_GUARD_PARTIAL_CLOSE, // Partial Close + X_GUARD_ACTION_TRAIL_STOP, // Trail StopLoss + X_GUARD_ACTION_FORCE_CLOSE, // Force Close + X_GUARD_ACTION_ADD_SUPPORT_SIGNAL, // Add Support Signal + X_GUARD_ACTION_CANCEL_PENDING_ORDERS, // Cancel Pending Orders +}; + +// +enum ENUM_X_POSITION_TYPES +{ + X_POSITION_TYPE_NONE = 0, + X_POSITION_TYPE_ALL = 1, + X_POSITION_TYPE_LONG = 2, + X_POSITION_TYPE_SHORT = 3, +}; + +// +string ToString(ENUM_X_POSITION_TYPES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POSITION_TYPE_ALL: + result = "All"; + break; + + // + case X_POSITION_TYPE_NONE: + result = "NONE"; + break; + + // + case X_POSITION_TYPE_SHORT: + result = "Short"; + break; + + // + case X_POSITION_TYPE_LONG: + result = "Long"; + break; + } + + // + return result; +} + +// +bool IsLong(ENUM_X_POSITION_TYPES value) +{ + return value == X_POSITION_TYPE_LONG; +} + +// +bool ToPositionType( + ENUM_POSITION_TYPE &dest, + ENUM_X_POSITION_TYPES source // +) +{ + // + bool result = false; + + // + result = source == X_POSITION_TYPE_LONG || + source == X_POSITION_TYPE_SHORT; + if (!result) + { + return result; + } + + // + dest = + source == X_POSITION_TYPE_LONG + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + return result; +} + +// +ENUM_X_POSITION_TYPES ToPositionType(ENUM_POSITION_TYPE value) +{ + return IsLong(value) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; +} + +// +ENUM_X_POSITION_TYPES GetOppositPositionType(ENUM_POSITION_TYPE type) +{ + // + ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; + + // + bool isLong = IsLong(type); + bool isShort = IsShort(type); + + // + result = + // + isLong + ? X_POSITION_TYPE_SHORT + : isShort + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_NONE + // + ; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_POSITION_TYPE value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = IsLong(value) + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = value == X_POSITION_TYPE_ALL + ? X_DIRECTION_ALL + : value == X_POSITION_TYPE_LONG + ? X_DIRECTION_BULLISH + : value == X_POSITION_TYPE_SHORT + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + return result; +} + +// +// Structs ... + +// +struct XRR +{ + // + double tps[]; + + // + double sl; + double entry; + + // + string prefix; + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + ENUM_X_POSITION_TYPES type; + + // + // Constructor ... + XRR() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + sl = 0; + entry = 0; + + // + time = NULL; + prefix = NULL; + period = NULL; + symbol = NULL; + + // + type = X_POSITION_TYPE_NONE; + + // + Clean(tps); + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + double _sl, + double _entry, + ENUM_X_POSITION_TYPES _type, + string _prefix = NULL // + ) + { + // + bool result = false; + + // + result = + _sl > 0 && + _entry > 0 && + IsValid(_symbol) && + IsValid(_period) && + _type != X_POSITION_TYPE_ALL && + _type != X_POSITION_TYPE_NONE && + (_type == X_POSITION_TYPE_LONG + ? _entry > _sl + : _entry < _sl); + if (!result) + { + return result; + } + + // + Default(); + + // + sl = _sl; + type = _type; + entry = _entry; + symbol = _symbol; + period = _period; + prefix = _prefix; + + // + time = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + // + void Default() + { + // + Add( + 1.0, + tps // + ); + Add( + 1.5, + tps // + ); + Add( + 2.0, + tps // + ); + Add( + 3.0, + tps // + ); + Add( + 4.0, + tps // + ); + Add( + 5.0, + tps // + ); + Add( + 6.0, + tps // + ); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + sl > 0 && + entry > 0 && + IsValid(time) && + IsValid(symbol) && + IsValid(period) && + IsValidSize(ArraySize(tps)) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE && + (type == X_POSITION_TYPE_LONG + ? entry > 0 + : entry < sl); + + // + return result; + } + + // + string GetTag() + { + // + string result = NULL; + + // + if (!IsValid()) + { + // + result = GetTypeName(this); + return result; + } + + // + string sep = "_"; + + // + result = + GetTypeName(this) + sep + (IsValid(prefix) ? prefix + sep : "") + symbol + sep + ToString(period) + sep + ToFormatString(time) + sep + ToString(type); + + // + return result; + } +}; + +// +// Model an Open Position ... +struct XPosition +{ + // + // Props ... + + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Sifnal Provider ... + string provider; + + // + // Position Comment ... + string comment; + + // + // Constructor ... + XPosition() + { + Clean(); + } + + // + // Initializers ... + + bool ByIndex(int index) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + ulong mTicket = mPositionInfo.Ticket(); + + // + result = ByTicket(mTicket); + + // + return result; + } + + bool ByTicket(ulong mTicket) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByTicket(mTicket); + if (!result) + { + return result; + } + + // + swap = mPositionInfo.Swap(); + magic = mPositionInfo.Magic(); + openAt = mPositionInfo.Time(); + sl = mPositionInfo.StopLoss(); + ticket = mPositionInfo.Ticket(); + symbol = mPositionInfo.Symbol(); + tp = mPositionInfo.TakeProfit(); + profit = mPositionInfo.Profit(); + volume = mPositionInfo.Volume(); + comment = mPositionInfo.Comment(); + entry = mPositionInfo.PriceOpen(); + type = mPositionInfo.PositionType(); + price = mPositionInfo.PriceCurrent(); + commission = mPositionInfo.Commission(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + magic = 0; + ticket = 0; + tp = 0; + sl = 0; + swap = 0; + entry = 0; + price = 0; + profit = 0; + volume = 0; + openAt = 0; + commission = 0; + + // + type = NULL; + period = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) + // + ; + + // + return result; + } + + // + // Retrieve Entry Price ... + double GetEntry() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetEntry( + symbol, + type + // + ); + + // + return result; + } + + // + // Retrieve Exit ... + double GetExit() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetExit( + symbol, + type + // + ); + + // + return result; + } + + // + // Get Spread by Point ... + double GetSpread() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = PriceToPoint(GetSpread(symbol)); + + // + return result; + } + + // + double GetPointsValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetPoints(symbol); + + // + return result; + } + + // + double GetProfitInPoint() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // Tick size + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Tick value + double pointSize = SymbolInfoDouble(symbol, SYMBOL_POINT); // Point size + double pointValue = tickValue * pointSize / tickSize; // Point value + + // + result = profit / (volume * tickValue); + + // + return result; + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + double GetRewardInPoint() + { + // + double result = 0; + + // + result = GetReward() / GetPoints(); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + // Calculate TP Levels ... + int CalculateTPLevels(double &tps[]) + { + + // + int result = 0; + + // + Clean(tps); + + // + bool isValid = IsValid(); + if (!isValid) + { + return result; + } + + // + double risk = GetRisk(); + int r2r = (int)GetRiskRewardRatio(); + bool isLong = IsLong(type); + for (int i = 0; i < r2r; i++) + { + // + double iValue = + isLong + ? entry + risk + (i * risk) + : entry - risk - (i * risk); + // + Add( + iValue, + tps // + ); + } + + // + result = ArraySize(tps); + + // + return result; + } + + // + // Calculate Reached TP Levels ... + void CalculateReahedTP( + double &reachedLevel, + double &reachedPrice // + ) + { + // + reachedLevel = -1; + reachedPrice = 0; + double tps[]; + bool isLong = IsLong(type); + double exitPrice = GetExit(); + int tpLevels = CalculateTPLevels(tps); + if (!IsValidSize(tpLevels) || exitPrice <= 0) + { + return; + } + + // + for (int i = 0; i < tpLevels - 1; i++) + { + // + double cTP = tps[i]; + double nTP = tps[i + 1]; + + // + bool isReached = + isLong + ? exitPrice > cTP && + exitPrice < nTP + : exitPrice < cTP && + exitPrice > nTP; + if (isReached) + { + // + reachedLevel = i + 1; + reachedPrice = cTP; + } + } + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XPosition &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XPosition &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Signal ... +struct XSignal +{ + // + // Props ... + + // + ulong positionId; // if Executed this filled ... + + // + datetime time; // Issue Time ... + + // + double tp; // Take Profit ... + double sl; // Stop Loss ... + double entry; // Exntry or Execution Price ... + double volume; // Position Volume ... + + // + string symbol; // Trading Symbol ... + string comment; // Comment ... + string provider; // Signaller ... + + // + ENUM_TIMEFRAMES period; // Trading TimeFrame ... + ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ... + ENUM_X_ORDER_MODES mode; // Execution Mode ... + + // + XSignal supports[]; // a Collecion of Support Signals ... + + // + int pushers; // Signal Pushers ... + string conditions; // Signal Conditions ... + + // + // Additional ... + + // + // TP ... + double fullTPLevel; // Full TP ... + double partialCloseMultiplier; // Amount of Partial Close ... + double partialCloseOnTPLevel; // Do Partial Close on TP Level ... + + // + // RF ... + double tpLevelForBreakEven; // TP Level for Break Even ... + bool riskFreeOnBreakEven; // Risk Free Signal On Break Even ... + + // + // Traget ... + double targets[]; // Force Risk Free On Targets ... + bool ignoreEAVolume; // Ignore EA Volume ... + + // + // SL Trail ... + bool trailSL; // Do SL Trail ... + double trailSLStartOnReachTPLevel; // Start SL Trail After Reached TP Level ... + + // + // Constructor ... + XSignal() + { + Clean(); + } + + // + bool Prepare( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + bool result = false; + + // + result = + // + IsValid(mMode) && + IsValid(mSymbol) && + IsValid(mPeriod) && + NotEmpty(mEntry) && + NotEmpty(mVolume) && + IsValid(mProvider) + // + ; + if (!result) + { + return result; + } + + // + if (mTP < 0) + { + mTP = 0; + } + + // + if (mSL < 0) + { + mSL = 0; + } + + // + type = mType; + mode = mMode; + symbol = mSymbol; + period = mPeriod; + provider = mProvider; + + // + // Normalization Values ... + sl = NormalizePrice(mSL, mSymbol); + tp = NormalizePrice(mTP, mSymbol); + mEntry = NormalizePrice(mEntry, mSymbol); + mVolume = NormalizeVolume(mVolume, mSymbol); + + // + entry = mEntry; + volume = mVolume; + + // + result = Normalize(); + + // + return result; + } + + // + bool PrepareComplex( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + // + // TP ... + double mFullTPLevel = 0, // Full TP Level + double mPartialCloseOnTPLevel = 0, // Partial Close On TP Level + double mPartialCloseMultiplier = 0, // Partial Close Multiplier + // + // RF ... + bool mRiskFreeOnBreakEven = false, // Risk Free Signal On Break Even ... + double mTpLevelForBreakEven = 0, // TP Level for Break Even ... + // + // SL Trail ... + bool mTrailSL = false, // Trail SL + double mTrailSLStartOnReachTPLevel = 0 // Trail SL Starts after Reached TP Level + ) + { + // + bool result = false; + + // + // Validate Args ... + result = + // + // Common ... + mSL > 0 && + mEntry > 0 && + mVolume > 0 && + IsValid(mSymbol) && + IsValid(mPeriod) && + IsValid(mProvider) && + mMode != X_ORDER_MODE_NOTHING + // + && + // + // TP ... + mFullTPLevel > 0 + // + ; + if (!result) + { + return result; + } + + // + // Prepare Regular Signal Values ... + double _risk = MathAbs(mEntry - mSL); + double _reward = _risk * mFullTPLevel; + + // + bool isLong = IsLong(mType); + + // + sl = mSL; + type = mType; + mode = mMode; + entry = mEntry; + symbol = mSymbol; + period = mPeriod; + volume = mVolume; + provider = mProvider; + fullTPLevel = mFullTPLevel; + tp = isLong + ? mEntry + _reward + : mEntry - _reward; + + // + result = Normalize(); + if (!result) + { + return result; + } + + // + // Calculate Other Conditions ... + + // + bool canPartialClose = + // + mPartialCloseOnTPLevel > 0 && + mPartialCloseMultiplier > 0 && + mPartialCloseOnTPLevel < mFullTPLevel + // + ; + if (canPartialClose) + { + // + partialCloseOnTPLevel = mPartialCloseOnTPLevel; + partialCloseMultiplier = mPartialCloseMultiplier; + } + + // + bool canRFOnBEP = + // + mRiskFreeOnBreakEven && + mTpLevelForBreakEven > 0 + // + ; + if (canRFOnBEP) + { + // + riskFreeOnBreakEven = mRiskFreeOnBreakEven; + tpLevelForBreakEven = mTpLevelForBreakEven; + } + + // + bool canTrailSL = + // + mTrailSL && + mTrailSLStartOnReachTPLevel > 0 && + mTrailSLStartOnReachTPLevel < mFullTPLevel + // + ; + if (canTrailSL) + { + // + trailSL = mTrailSL; + trailSLStartOnReachTPLevel = mTrailSLStartOnReachTPLevel; + } + + // + result = IsValid(); + + // + return result; + } + + // + bool PrepareLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + mMode, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + mMode, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Market Mode ... + + // + bool PrepareMarketLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareMarketShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Stop Mode ... + + // + bool PrepareStopLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareStopShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Limit Mode ... + + // + bool PrepareLimitLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareLimitShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Generate Opposit Direction ... + bool GenerateOpposit( + XSignal &mSignal // Oppsoit Signal + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + ENUM_POSITION_TYPE mType = GetOpposit(this.type); + double mEntry = GetExit(this.symbol, mType); + + // + bool isLong = IsLong(mType); + + // + // Calculate Risk Reward Ratio ... + double risk = GetRisk(); + double reward = GetReward(); + + // + double mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + double mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + result = mSignal.Prepare( + this.symbol, + this.provider, + this.period, + mType, + this.mode, + mEntry, + this.volume, + mSL, + mTP // + ); + + // + return result; + } + + // + // Prepare Opposit Signal based On a Position ... + bool PrepareOpposit( + XPosition &source // Source Data + ) + { + // + bool result = false; + + // + ENUM_POSITION_TYPE mType = GetOpposit(source.type); + double mEntry = GetEntry(source.symbol, mType); + + // + bool isLong = IsLong(mType); + + // + double risk = source.GetRisk(); + double reward = source.GetReward(); + + // + double mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + double mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + return Prepare( + source.symbol, + source.provider, + source.period, + mType, + X_ORDER_MODE_MARKET, + mEntry, + source.volume, + mSL, + mTP // + ); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + entry = 0; + volume = 0; + pushers = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + conditions = NULL; + + // + Clean(targets); + ignoreEAVolume = false; + + // + trailSL = false; + riskFreeOnBreakEven = false; + + // + fullTPLevel = 0; + tpLevelForBreakEven = 0; + partialCloseOnTPLevel = 0; + partialCloseMultiplier = 0; + trailSLStartOnReachTPLevel = 0; + + // + Clean(supports); + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(period) && + IsValid(symbol) && + NotEmpty(volume) && + NotEmpty(entry) + // + ; + + // + if (!result) + { + return result; + } + + // + return result; + } + + // + // DO All Calculations and Normalizations ... + bool Normalize() + { + // + bool result = false; + + // + // Normalizations ... + symbol = NormalizeSymbol(symbol); + period = NormalizePeriod(period); + + // + time = NormalizeTime(time); + + // + sl = NormalizePrice(sl, symbol); + tp = NormalizePrice(tp, symbol); + entry = NormalizePrice(entry, symbol); + volume = NormalizeVolume(volume, symbol); + + // + result = IsValid(); + + // + return result; + } + + // + // Check Signal Executed or not ... + bool IsExecuted() + { + // + bool result = false; + + // + result = + // + IsValid() && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Generate Comment for Signal ... + string GenerateComment() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (IsValid(provider)) + { + // + // Generate Provider Tag ... + result += GenerateProviderTag(provider); + } + + // + if (IsValid(period)) + { + // + // Generate Period Tag ... + result += GeneratePeriodTag(period); + } + + // + return result; + } + + // + int GetAge() + { + // + return GetAge( + this, + this.period // + ); + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + // Check Can Partial Close on Specified TP Level ... + bool CanPartialClose() + { + // + bool result = false; + + // + result = + IsValid() && + fullTPLevel > 0 && + partialCloseOnTPLevel > 0 && + partialCloseMultiplier > 0 && + partialCloseOnTPLevel < fullTPLevel; + + // + return result; + } + + // + // Check Can Risk Free On Break Even Point ... + bool CanRiskFreeOnBreakEvenPoint() + { + // + bool result = false; + + // + result = + IsValid() && + riskFreeOnBreakEven && + tpLevelForBreakEven > 0; + + // + return result; + } + + // + // Check Can Trail SL ... + bool CanTrailSL() + { + // + bool result = false; + + // + result = + IsValid() && + trailSL && + fullTPLevel > 0 && + trailSLStartOnReachTPLevel > 0 && + trailSLStartOnReachTPLevel < fullTPLevel; + + // + return result; + } + + // + string GetTag() + { + // + string result = NULL; + + // + result = "XSignal_" + + symbol + "_" + + ToString(period) + "_" + + ToString(type) + "_" + + ToString(sl) + "_" + + ToString(tp) + "_" + + ToString(entry); + + // + return result; + } + + // + // Retrieve String Representation of Signal ... + string ToString() + { + // + string result = NULL; + + // + result = + // + ToString("Symbol", symbol) + + ToString("Period", period) + + ToString("Provider", provider) + + ToString("Type", type) + + ToString("Mode", mode) + + ToString("Volume", volume) + + ToString("Entry", entry) + + ToString("TP", tp) + + ToString("SL", sl) + + ToString("Time", time) + + ToString("Comment", comment) + + // + "" + // + ; + + // + return result; + } +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long positionId; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string symbol; + + // + // Signal Provider ... + string provider; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOrder() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static COrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Retrieve Specific History Order ... + bool HistoryByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static CHistoryOrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + tp = 0; + sl = 0; + magic = 0; + ticket = 0; + positionId = 0; + openPrice = 0; + currentPrice = 0; + initialVolume = 0; + currentVolume = 0; + stopLimitPrice = 0; + + // + setupAt = NULL; + expiredAt = NULL; + executedAt = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + state = NULL; + period = NULL; + filling = NULL; + lifetime = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XOrder &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + state == value.state && + magic == value.magic && + ticket == value.ticket && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XOrder &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ENUM_ORDER_STATE mState = NULL, // Order State + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // State Filter ... + IsStateFilterPassed( + mState, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + string provider; + + // + ENUM_TIMEFRAMES period; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; + + // + // Constructor ... + XDeal() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Deal Index + ) + { + // + bool result = false; + + // + int dealsCount = HistoryDealsTotal(); + result = dealsCount > 0; + if (!result) + { + return result; + } + + // + static CDealInfo mDealInfo; + + // + result = mDealInfo.SelectByIndex(index); + if (!result) + { + // + return result; + } + + // + // Reading Order Info ... + swap = mDealInfo.Swap(); + magic = mDealInfo.Magic(); + order = mDealInfo.Order(); + ticket = mDealInfo.Ticket(); + time = mDealInfo.Time(); + price = mDealInfo.Price(); + symbol = mDealInfo.Symbol(); + profit = mDealInfo.Profit(); + volume = mDealInfo.Volume(); + comment = mDealInfo.Comment(); + positionId = mDealInfo.PositionId(); + entry = mDealInfo.Entry(); + commission = mDealInfo.Commission(); + type = mDealInfo.DealType(); + reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + magic = 0; + positionId = 0; + ticket = 0; + order = 0; + time = 0; + price = 0; + profit = 0; + swap = 0; + commission = 0; + volume = 0; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + entry = NULL; + period = NULL; + reason = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XDeal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + reason == value.reason && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XDeal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_DEAL_TYPE mType = NULL, // Deal Type + ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry + ENUM_DEAL_REASON mReason = NULL, // Deal Reason + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Entry Filter ... + IsEntryFilterPassed( + mEntry, + this + // + ) + // + && + // + // Reason Filter ... + IsReasonFilterPassed( + mReason, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; + + // + // Constructor ... + XOnTradeHandlerState() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + hasNewDeal = false; + hasNewOrder = false; + hasNewPosition = false; + hasNewHistoryOrder = false; + + // + newDeals = 0; + newOrders = 0; + newPositions = 0; + newHistoryOrders = 0; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ( + // + hasNewDeal + ? newDeals > 0 + : true + // + ) + // + && + // + ( + // + hasNewOrder + ? newOrders > 0 + : true + // + ) + // + && + // + ( + // + hasNewPosition + ? newPositions > 0 + : true + // + ) + // + && + // + ( + // + hasNewHistoryOrder + ? newHistoryOrders > 0 + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Model Guard Info ... +struct XGuard +{ + // + string symbol; // Trading Symbol ... + string provider; // Signal Provider ... + ENUM_TIMEFRAMES period; // Trading Timeframe ... + ENUM_X_POSITION_TYPES type; // Position Type ... + ENUM_X_GUARD_ACTIONS action; // Which Action to Do ... + + // + double dblPayLoad; + string strPayload; + + // + // Constructor ... + XGuard() + { + Clean(); + } + + // + // Initialize ... + + // + // Global Initializer ... + bool Init( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Timeframe ... + ENUM_X_GUARD_ACTIONS mAction, // Which Action to Do ... + ENUM_X_POSITION_TYPES mType = NULL, // Position Type ... + string mProvider = NULL, // Signal Provider ... + double mDblPayLoad = NULL, + string mStrPayload = NULL // + ) + { + // + type = mType; + symbol = mSymbol; + period = mPeriod; + action = mAction; + provider = mProvider; + dblPayLoad = mDblPayLoad; + strPayload = mStrPayload; + + // + bool result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + provider = NULL; + period = NULL; + action = X_GUARD_ACTION_NOTHING; + + // + strPayload = NULL; + dblPayLoad = EMPTY_VALUE; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + action != X_GUARD_ACTION_NOTHING + // + ; + + // + return result; + } +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; // Main Position's Ticket + + // + XPosition position; // Main Position (if Exists) + + // + int supportOrdersCount; // Supported Orders (Untriggered) + int supportPositionsCount; // Supported Positions + + // + XOrder supportOrders[]; // Supported Orders (Untriggered) + XPosition supportPositions[]; // Supported Positions + + // + // Constructor ... + XPositionPack() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + + // + position.Clean(); + + // + supportOrdersCount = 0; + supportPositionsCount = 0; + + // + Clean(supportOrders); + Clean(supportPositions); + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + NotEmpty(ticket) && + ( + // + supportOrdersCount > 0 + ? ArraySize(supportOrders) == supportOrdersCount + : true + // + ) + // + && + // + ( + // + supportPositionsCount > 0 + ? ArraySize(supportPositions) == supportPositionsCount + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Check Position SL Trails Structure ... +struct XTrail +{ + // + ulong ticket; // Position Ticket ... + ENUM_POSITION_TYPE type; // Type ... + datetime time; // Trail Time ... + double before; // SL Value Before Trailing ... + double after; // SL Value After Trailing ... + int level; // Number of Trails SL ... + double profit; // Profit in SL Time ... + + // + // Constructor ... + XTrail() + { + Clean(); + } + + // + // Tools ... + + // + bool Init( + ulong mTicket, // Ticket + ENUM_POSITION_TYPE mType, // Type + double mProfit, // Profit + double mBefore, // Before + double mAfter // After + ) + { + // + Clean(); + + // + type = mType; + after = mAfter; + ticket = mTicket; + before = mBefore; + profit = mProfit; + + // + level++; + + // + time = TimeCurrent(); + + // + return IsValid(); + } + + // + bool Update( + double mSl, // new SL ... + double mProfit // Profit + ) + { + // + bool result = false; + + // + time = TimeCurrent(); + + // + double cAfter = after; + after = mSl; + before = cAfter; + profit = mProfit; + + // + level++; + + // + result = IsValid(); + + // + return result; + } + + // + string GenerateTag() + { + // + string result = NULL; + + // + string ticketLevelStr = ToString(ticket) + "," + ToString(level); + + // + result = Surround( + XSLTrailToken, + ticketLevelStr // + ); + + // + return result; + } + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + time = 0; + before = 0; + after = 0; + level = 0; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + time > 0 && + level > 0 + // + ; + + // + return result; + } +}; + +// +struct XSymbolPositions +{ + // + string symbol; + + // + double profit; + double volume; + + // + double longsProfit; + double longSupportsProfit; + + // + double shortsProfit; + double shortSupportsProfit; + + // + double longsVolume; + double longSupportsVolume; + + // + double shortsVolume; + double shortSupportsVolume; + + // + double requiredProfitForHedge; + + // + XPosition longs[]; + XPosition shorts[]; + XPosition supports[]; + XPosition positions[]; + XPosition longSupports[]; + XPosition shortSupports[]; + + // + bool forceHedge; + + // + XSymbolPositions() + { + Clean(); + } + + // + bool Update( + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // + ) + { + // + bool result = false; + + // + bool hasChild = HasChild(); + if (!hasChild) + { + return result; + } + + // + XPosition _supports[]; + XPosition _positions[]; + + // + XPosition _tmp[]; + + // + Copy( + positions, + _tmp // + ); + + // + Clean(positions); + + // + int tmpsCount = ArraySize(_tmp); + for (int i = 0; i < tmpsCount; i++) + { + // + XPosition iPosition = _tmp[i]; + + // + bool isSupport = IsSupport(iPosition.comment); + if (!isSupport) + { + // + AddRef( + iPosition, + _positions // + ); + } + else + { + // + AddRef( + iPosition, + _supports // + ); + } + } + + // + Clean(_tmp); + + // + Copy( + _positions, + positions // + ); + Clean(_positions); + + // + // Extract Types ... + ExtractPositions( + positions, + longs, + shorts // + ); + + // + Copy( + _supports, + supports // + ); + Clean(_supports); + + // + // Extract Types ... + ExtractPositions( + supports, + longSupports, + shortSupports // + ); + + // + int numOfLongs = 0; + int numOfShorts = 0; + CountPositions( + positions, + numOfLongs, + longsProfit, + longsVolume, + numOfShorts, + shortsProfit, + shortsVolume // + ); + + // + numOfLongs = 0; + numOfShorts = 0; + CountPositions( + supports, + numOfLongs, + longSupportsProfit, + longSupportsVolume, + numOfShorts, + shortSupportsProfit, + shortSupportsVolume // + ); + + // + XPosition _allPositions[]; + Copy( + positions, + _allPositions, + false // + ); + Copy( + supports, + _allPositions, + false // + ); + + // + profit = longsProfit + shortsProfit + longSupportsProfit + shortSupportsProfit; + volume = longsVolume + shortsVolume + longSupportsVolume + shortSupportsVolume; + requiredProfitForHedge = SpecifiedCalculateRequiredProfitForHedge( + _allPositions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + + // + Clean(_allPositions); + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + forceHedge = false; + + // + profit = 0; + longsProfit = 0; + shortsProfit = 0; + + // + volume = 0; + longsVolume = 0; + shortsVolume = 0; + + // + requiredProfitForHedge = 0; + + // + Clean(longs); + Clean(shorts); + Clean(positions); + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol); + + // + return result; + } + + // + // Has Child ... + bool HasChild() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int count = Count(); + result = IsValidSize(count); + + // + return result; + } + + // + // Count ... + int Count() + { + return ArraySize(positions); + } + + // + int CountSupports() + { + return ArraySize(supports); + } + + // + int CountLongs() + { + return ArraySize(longs); + } + + // + int CountShorts() + { + return ArraySize(shorts); + } + + // + int CountLongSupports() + { + return ArraySize(longSupports); + } + + // + int CountShortSupports() + { + return ArraySize(shortSupports); + } + + // + int GetOldest( + XPosition &_oldest, // + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = GetOldest( + _oldest, + longs // + ); + } + else + { + // + result = GetOldest( + _oldest, + shorts // + ); + } + + // + return result; + } + + // + int GetYoungest( + XPosition &_youngest, // + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = GetYoungest( + _youngest, + longs // + ); + } + else + { + // + result = GetYoungest( + _youngest, + shorts // + ); + } + + // + return result; + } + + // + int GetMaxInProfit( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMaxProfitIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMaxProfitIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMinInProfit( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMinProfitIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMinProfitIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMaxInDrawdown( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMaxInDrawdownIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMaxInDrawdownIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMinInDrawdown( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMinInDrawdownIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMinInDrawdownIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // +}; + +// +struct XSymbolLastPosition +{ + // + string symbol; + string provider; + datetime time; + + // + XSymbolLastPosition() + { + Clean(); + } + + // + // Tools ... + + void Clean() + { + // + time = NULL; + symbol = NULL; + provider = NULL; + + // + ZeroMemory(this); + } +}; + +// +// an Structure for Holding Positions Data ... +struct XTradeData +{ + // + datetime time; // Issue Time (Open Position) + string symbol; // Trading Symbol + double entry; // Entry Price + double volume; // Volume + string provider; // Signaller + ENUM_TIMEFRAMES period; // Trading Timeframe + ENUM_X_POSITION_TYPES type; // Position Type + + // + ulong ticket; // Position Ticket + double swap; // Swap + double profit; // Profit on Close + double commission; // Commission + double maxDrawdown; // Max Position Drawdown + string message; // Close Reason + datetime endTime; // End Time + + // + XSignal signal; // Signal Object + int pushers; // Signal Pushers + string conditions; // Signal Conditions + + // + // Constructor ... + void XTradeInfo() + { + Clean(); + } + + // + // Filling Trade Handler ... + bool Fill(XSignal &_signal) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _signal.IsValid(); + if (!result) + { + return result; + } + + // + signal = _signal; + time = _signal.time; + entry = _signal.entry; + symbol = _signal.symbol; + volume = _signal.volume; + period = _signal.period; + pushers = _signal.pushers; + provider = _signal.provider; + conditions = _signal.conditions; + type = ToPositionType(_signal.type); + + // + if (_signal.IsExecuted()) + { + ticket = _signal.positionId; + } + + // + return result; + } + + // + // Filling Trade Handler ... + bool Fill(XPosition &_position) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + time = _position.openAt; + symbol = _position.symbol; + entry = _position.entry; + volume = _position.volume; + provider = _position.provider; + period = _position.period; + type = ToPositionType(_position.type); + + // + ticket = _position.ticket; + + // + return result; + } + + // + // Update Data ... + bool Update(XPosition &_position) + { + // + bool result = false; + + // + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + profit = _position.profit; + swap = _position.swap; + + // + if (profit < 0 && + (maxDrawdown == 0 || + MathAbs(profit) > MathAbs(maxDrawdown))) + { + maxDrawdown = profit; + } + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + time = NULL; + type = NULL; + symbol = NULL; + period = NULL; + endTime = NULL; + message = NULL; + provider = NULL; + + // + swap = 0; + entry = 0; + ticket = 0; + profit = 0; + volume = 0; + commission = 0; + maxDrawdown = 0; + + // + signal.Clean(); + + // + ResetTrail(); + ResetRecovery(); + + // + ZeroMemory(this); + } + + // + // Validation ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + IsValid(time) && + IsValid(symbol) && + IsValid(period) + // + ; + + // + return result; + } + + // + // Retrieve Trade Data Age ... + int GetAge() + { + // + int result = -1; + + // + if (!IsValid(symbol) || + !IsValid(time) || + !IsValid(endTime) || + !IsValid(period)) + { + return result; + } + + // + int startIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + int endIndex = iBarShift( + symbol, + period, + endTime, + false // + ); + + // + result = MathAbs(startIndex - endIndex); + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Ticket ... + bool IsOwn( + ulong _ticket // + ) + { + // + bool result = false; + + // + result = _ticket == ticket; + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Symbol/Provider and Period ... + bool IsOwn( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + IsValid(_provider) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE && + // + type == _type && + period == _period && + symbol == _symbol && + provider == _provider + // + ; + + // + return result; + } + + // + // Data Collector ... + + // + // Get Data File Name ... + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(ticket) + "_" + + ToString(period) + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Get Signal File Name ... + string GetSignalFileName() + { + // + string result = NULL; + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + provider + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Convert(s) To String Representation(s) ... + string ToString( + bool onlySignals = false // + ) + { + // + string result = NULL; + + // + int age = GetAge(); + + // + result = + // + (onlySignals + ? "" + : ToString("Ticket", ticket)) + + ToString("Symbol", symbol) + + ToString("Period", period) + + ToString("Entry", entry) + + ToString("Provider", provider) + + ToString("Type", ToString(type)) + + ToString("Time", time) + + // + // Attach Trade Info ... + (onlySignals + ? "" + : + // + "-------------" + "\n" + + ToString("Volume", volume) + + ToString("Profit", profit) + + ToString("Commission", commission) + + ToString("Swap", swap) + + ToString("Max Drawdown", maxDrawdown) + + ToString("End Time", endTime) + + ToString("Age", age) + + ToString("Message", message) + + "" + // + ) + + // + // Attach Conditions to Signals ... + (!onlySignals + ? "" + : + // + "-------------" + "\n" + + ToString("Pushers", pushers) + + "Conditions:" + "\n" + + "-------------" + "\n" + + conditions + + "" + // + ) + + // + "" + // + ; + + // + return result; + } + + // + // There are some Controlling Situations for each Trade + // which implemented here ... + + // + // Trailing Stop .... + + // + bool allowTrailStop; // Specified Position Can Trail Stop or not + bool ignoreTPOnTrail; // Ignore TP when SL Trailed + bool trailBasedOnProfit; // Do Trail Based on Profit Points + int trailLevel; // Last Trail Level + double trailStartInPoint; // Trail Starts When Profits Growing in Point + double trailStepInPoint; // Profit Must Grows Point to do Trailling + + // + // Reset all Trailing Configurations .... + void ResetTrail() + { + // + trailLevel = 0; + trailStepInPoint = 0; + trailStartInPoint = 0; + allowTrailStop = false; + ignoreTPOnTrail = false; + trailBasedOnProfit = false; + } + + // + // Recovery ... + + // + bool allowRecover; // Allow Recover Specified Position + double recoveryTPPoint; // Recovery TP Point + double recoverySLPoint; // Recovery SL Point + int maxAllowedRecover; // Max Allowed Recovery + int recoveryLevel; // Number of Recovery Signals + double recoveryVolumeMultiplier; // Recovery Volume Multiplier + double recoveryVolume; // Next Recovery Positioin Volume + ENUM_X_POSITION_TYPES recoveryLookingType; // Looking for Next Recovery Type + + // + void ResetRecovery() + { + // + allowRecover = false; + recoveryLevel = 0; + recoveryVolume = 0; + recoveryTPPoint = 0; + recoverySLPoint = 0; + recoveryVolumeMultiplier = 0; + recoveryLookingType = X_POSITION_TYPE_NONE; + } + + // +}; + +// +// TypeDefs ... + +// +typedef void (*TOnSignal)(XSignal &signal); + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +typedef void (*TOnForceClose)( + const ulong ticket, + const XPosition &position, + const string comment // +); + +// +typedef void (*TOnPartialClose)( + const ulong ticket, + const double profit, + const string comment // +); + +// +typedef void (*TOnModify)( + const ulong ticket, + const double profit, + const string comment // +); + +// +// Classes ... + +// +// Tools ... + +// +bool IsValid(ENUM_X_ORDER_MODES value) +{ + return value != X_ORDER_MODE_NOTHING; +} + +// +// Ages ... + +// +// Retrieve a Position Age ... +int GetAge( + XSignal &signal, // Selected Signal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + signal.symbol, + period, + signal.time); + + // + return result; +} + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.symbol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +int FindMaxProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (max == 0 || + max < iPosition.profit) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInProfitPositions( + XPosition &positions[], // Position Collection + XPosition &inProfits[] // Result +) +{ + // + int result = 0; + + // + Clean(inProfits); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + inProfits // + ); + } + } + + // + result = ArraySize(inProfits); + + // + return result; +} + +// +int FindMaxInDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (max == 0 || + MathAbs(max) < MathAbs(iPosition.profit)) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinInDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInDrawdownPositions( + XPosition &positions[], // Position Collection + XPosition &inDradowns[] // Result +) +{ + // + int result = 0; + + // + Clean(inDradowns); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + inDradowns // + ); + } + } + + // + result = ArraySize(inDradowns); + + // + return result; +} + +// +// Check Filters ... + +// +// Magic Filter ... +template +bool IsMagicFilterPassed( + ulong magic, + bool filterByMagic, + T &item + // +) +{ + // + return !filterByMagic + ? true + : !NotEmpty(magic) + ? false + : magic == item.magic; +} + +// +// Symbol Filter ... +template +bool IsSymbolFilterPassed( + string symbol, + T &item + // +) +{ + // + return !IsValid(symbol) + ? true + : symbol == item.symbol; +} + +// +// Provider Filter ... +template +bool IsProviderFilterPassed( + string provider, + T &item + // +) +{ + // + return !IsValid(provider) + ? true + : provider == item.provider; +} + +// +// Period Filter ... +template +bool IsPeriodFilterPassed( + ENUM_TIMEFRAMES period, + T &item + // +) +{ + // + return !IsValid(period) + ? true + : period == item.period; +} + +// +// Type Filter ... +template +bool IsTypeFilterPassed( + ENUM_POSITION_TYPE type, + T &item + // +) +{ + // + bool result = type == item.type; + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_X_POSITION_TYPES type, + T &item + // +) +{ + // + bool result = type == NULL || type == X_POSITION_TYPE_ALL + ? true + : ((type == X_POSITION_TYPE_LONG && ((int)item.type == (int)POSITION_TYPE_BUY || (int)item.type == (int)ORDER_TYPE_BUY)) || + (type == X_POSITION_TYPE_SHORT && ((int)item.type == (int)POSITION_TYPE_SELL || (int)item.type == (int)ORDER_TYPE_SELL))); + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_ORDER_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_DEAL_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} + +// +// Mode Filter ... +template +bool IsModeFilterPassed( + ENUM_X_ORDER_MODES mode, + T &item + // +) +{ + // + return mode == NULL + ? true + : mode == item.mode; +} + +// +// Entry Filter ... +template +bool IsEntryFilterPassed( + ENUM_DEAL_ENTRY entry, + T &item + // +) +{ + // + return entry == NULL + ? true + : entry == item.entry; +} + +// +// Reason Filter ... +template +bool IsReasonFilterPassed( + ENUM_DEAL_REASON reason, + T &item + // +) +{ + // + return reason == NULL + ? true + : reason == item.reason; +} + +// +// State Filter ... +template +bool IsStateFilterPassed( + ENUM_ORDER_STATE state, + T &item + // +) +{ + // + return state == NULL + ? true + : state == item.state; +} + +// + + +// +// +// Calculate Positions Profit Summary ... +double SpecifiedCalculatePositionsProfit( + XPosition &positions[] // Source +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result += iPosition.profit; + } + + // + return result; +} + +// +// Calculate Required Profit for Hedging ... +double SpecifiedCalculateRequiredProfitForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0; + if (!isHedgingEnable) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0) + { + // + result += + ((iPosition.volume / mMinProfitPerVolumeFactor) * + mMinProfitPerTrade) + + (-1 * iPosition.swap); + } + } + + // + return result; +} + +// +bool SpecifiedIsPositionsReadyForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double profit = SpecifiedCalculatePositionsProfit(positions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + positions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + + // + bool result = requiredProfit > 0 + ? profit >= requiredProfit + : profit > requiredProfit; + + // + return result; +} + +// +int FindCoverageDrawdownPosition( + XPosition &position, // In Drawdown Position + XPosition &inProfits[], // In Profit Positions + XPosition &coverage[], // Coverage Positons + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + int result = 0; + + // + Clean(coverage); + + // + if (!position.IsValid() || position.profit >= 0) + { + return result; + } + + // + int inProfitsCount = ArraySize(inProfits); + if (!IsValidSize(inProfitsCount)) + { + return result; + } + + // + // Copy in Profits to TMP ... + XPosition tmp[]; + Copy( + inProfits, + tmp // + ); + + // + bool isCoverPassed = false; + while (!isCoverPassed || ArraySize(tmp) > 0) + { + // + XPosition max; + int idx = FindMaxProfitIndex(tmp); + if (idx >= 0) + { + // + if (tmp[idx].profit > 0) + { + AddRef( + tmp[idx], + coverage // + ); + + // + ArrayRemove( + tmp, + idx, + 1 // + ); + } + } + + // + // Check Cover Passed ... + XPosition tmpPositions[]; + Copy( + coverage, + tmpPositions // + ); + AddRef( + position, + tmpPositions // + ); + + // + double profits = SpecifiedCalculatePositionsProfit(tmpPositions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + tmpPositions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + isCoverPassed = profits >= requiredProfit; + if (isCoverPassed) + { + break; + } + + // + if (!isCoverPassed && ArraySize(tmp) == 0) + { + break; + } + } + + // + result = ArraySize(coverage); + + // + return result; +} + +// +// Extract a Collection of Positions SL ... +int ExtractSLs( + XPosition &positions[], + double &sls[] // +) +{ + // + int result = 0; + + // + Clean(sls); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.sl > 0) + { + // + Add( + iPosition.sl, + sls // + ); + } + } + + // + result = ArraySize(sls); + + // + return result; +} + +// +// Extract a Colletion of Positions TP ... +int ExtractTPs( + XPosition &positions[], + double &tps[] // +) +{ + // + int result = 0; + + // + Clean(tps); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.tp > 0) + { + // + Add( + iPosition.tp, + tps // + ); + } + } + + // + result = ArraySize(tps); + + // + return result; +} + +// +// Retrieve String Representation ... +string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SIGNAL_EXECUTION_UNKNOWN: + result = "Unknown"; + break; + + // + case X_SIGNAL_EXECUTION_SUCCEED: + result = "Succed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_SPREAD: + result = "Spread more than Max Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED: + result = "not Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NO_EQUITY: + result = "No Equity for Trade"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR: + result = "Price Error"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR: + result = "Previous Position Profit not Passed for Accept Next"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_MAX_REACHED: + result = "Max Allowed Positions Reached"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED: + result = "Min Delay Between to Signal not Passed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS: + result = "Invalid Params"; + break; + } + + // + return result; +} + +// +// Converts Position Type to Order Type ... +ENUM_ORDER_TYPE ToOrderType(ENUM_POSITION_TYPE value) +{ + // + bool isLong = IsLong(value); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} +ENUM_ORDER_TYPE ToOrderType(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_POSITION_TYPE mType = + value == X_POSITION_TYPE_SHORT + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + bool isLong = IsLong(mType); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} + +// +// Tagging ... + +// +// Generate Specified Tag for Using in Comments ... +string GeneratePeriodTag(ENUM_TIMEFRAMES period) +{ + // + string strPeriod = ToString(period); + return Surround( + XPeriodToken, + strPeriod + // + ); +} + +// +// Extract Period from a Tagged string ... +ENUM_TIMEFRAMES ExtractPeriod(string value) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + string pStr = ParseStringSurrounded( + value, + XPeriodToken + // + ); + if (!IsValid(pStr)) + { + return result; + } + + // + result = ToPeriod(pStr); + + // + return result; +} + +// Generate Specified Tag for Using in Comments ... +string GenerateProviderTag(string provider) +{ + // + return Surround( + XProviderToken, + provider + // + ); +} + +// +// Extract Provider from a Tagged string ... +string ExtractProvider(string value) +{ + // + return ParseStringSurrounded( + value, + XProviderToken + // + ); +} + +// +// Generate Support Comment Tag ... +string GenerateSupportTag(ulong ticket) +{ + // + return Surround( + XSupportToken, + ticket + // + ); +} + +// +// Extract Support Positions from a Tagged string ... +ulong ExtractSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XSupportToken + // + ); +} + +// +// Extract Support ... +template +int ExtractSupports( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isSupport = ExtractSupportedTicket(iSource.comment) > 0; + ulong iEQMSupport = ExtractEQMSupportedTicket(iSource.comment) > 0; + if (isSupport || iEQMSupport) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Generate EQM Support Comment Tag ... +string GenerateEQMSupportTag(ulong ticket) +{ + // + return Surround( + XEQMSupportToken, + ticket + // + ); +} + +// +// Extract EQM Support Positions from a Tagged string ... +ulong ExtractEQMSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XEQMSupportToken + // + ); +} + +// +bool IsSupport(string value) +{ + // + bool result = false; + + // + bool isSupport = ExtractSupportedTicket(value) > 0; + bool isEQMSupport = ExtractEQMSupportedTicket(value) > 0; + + // + result = + // + isSupport + // + || + // + isEQMSupport + // + ; + + // + return result; +} + +// +ulong ExtractParentTicket(string value) +{ + // + ulong result = 0; + + // + if (!IsSupport(value)) + { + return result; + } + + // + result = ExtractSupportedTicket(value); + if (result > 0) + { + return result; + } + + // + result = ExtractEQMSupportedTicket(value); + + // + return result; +} + +// +// XRecovery ... + +// +string GenerateRecoveryTag(ulong ticket) +{ + // + return Surround( + XRecoveryToken, + ticket // + ); +} + +// +ulong ExtractRecoveredTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XRecoveryToken // + ); +} + +// +// Extract Recoveries ... +template +int ExtractRecoveries( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0; + if (isRecovery) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Extract Specified Position's Recoveries ... +int ExtractRecoveries( + ulong ticket, + XPosition &source[], + XPosition &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + XPosition iSource = source[i]; + + // + ulong parentTicket = ExtractRecoveredTicket(iSource.comment); + bool isRecovery = parentTicket > 0; + if (isRecovery && parentTicket == ticket) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// SL Trails ... + +// +// Extract SL Trail Level ... +int ExtractSLTrailLevel(string comment) +{ + // + int result = 0; + + // + if (!IsValid(comment)) + { + return result; + } + + // + result = ParseIntSurrounded( + comment, + XSLTrailToken + // + ); + + // + return result; +} + +// +// Generate SL Trail Comment Tag ... +string GenerateSLTrailTag(int level) +{ + // + string result = NULL; + + // + if (level <= 0) + { + return result; + } + + // + result = Surround( + XSLTrailToken, + level + // + ); + + // + return result; +} + +// +// Prepare SL Trail Comment ... +string PrepareSLTrailTag( + const string comment // Original Position Comment ... +) +{ + // + string result = NULL; + + // + int level = 0; + result = comment; + + // + // Check Comment Contains SL Trailing or not ... + int lastTrailLevel = ExtractSLTrailLevel(comment); + if (lastTrailLevel <= 0) + { + level++; + } + else + { + // + level = lastTrailLevel + 1; + string lastLevelStr = GenerateSLTrailTag(lastTrailLevel); + StringReplace( + result, + lastLevelStr, + "" + // + ); + } + + // + // Generate level Comment ... + string levelStr = GenerateSLTrailTag(level); + result += levelStr; + + // + return result; +} + +// +// Count Positions from a Collection ... +void CountPositions( + const XPosition &positions[], + int &longs, + double &longProfits, + double &longVolumes, // + // + int &shorts, + double &shortProfits, + double &shortVolumes // +) +{ + // + longs = 0; + longProfits = 0; + longVolumes = 0; + + // + shorts = 0; + shortProfits = 0; + shortVolumes = 0; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + // + longs++; + longProfits += iPosition.profit; + longVolumes += iPosition.volume; + } + else + { + // + shorts++; + shortProfits += iPosition.profit; + shortVolumes += iPosition.volume; + } + } +} + +// +// Extract Positions based On Type ... +void ExtractPositions( + XPosition &positions[], + XPosition &longs[], + XPosition &shorts[] // +) +{ + // + int count = ArraySize(positions); + if (!IsValidSize(count)) + { + return; + } + + // + Clean(longs); + Clean(shorts); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + AddRef( + iPosition, + longs // + ); + } + else + { + AddRef( + iPosition, + shorts // + ); + } + } +} + +// +int FindSymbolIndex( + string mSymbol, + XSymbolPositions &mItems[] // +) +{ + // + int result = -1; + + // + if (!IsValid(mSymbol)) + { + return result; + } + + // + int count = ArraySize(mItems); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XSymbolPositions iItem = mItems[i]; + + // + if (iItem.symbol == mSymbol) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +int ExtractSymbolPositions( + XPosition &positions[], + XSymbolPositions &items[], // Holds Result + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + Clean(items); + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (!iPosition.IsValid()) + { + continue; + } + + // + int itemIDX = FindSymbolIndex( + iPosition.symbol, + items // + ); + if (!IsValidIndex(itemIDX)) + { + // + // Add New One ... + XSymbolPositions item; + item.symbol = iPosition.symbol; + + // + AddRef( + item, + items // + ); + itemIDX = FindSymbolIndex(iPosition.symbol, items); + } + + // + AddRef( + iPosition, + items[itemIDX].positions // + ); + } + + // + result = ArraySize(items); + if (IsValidSize(result)) + { + // + for (int i = 0; i < result; i++) + { + // + items[i].Update( + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + } + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 new file mode 100644 index 0000000..fc5e824 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 @@ -0,0 +1,650 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XSCX121SMCBaseStrategy +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-121.smc.cobjects.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Helper(s) ... + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCBaseStrategy : public XCBaseAlert +{ + // + // Public ... + public: + // + XCAccount mAccount; + + // + // Constructor(s) ... + XCX121SMCBaseStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + { + // + mSymbol = _symbol; + mPeriod = _period; + + // + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCBaseStrategy() + { + DeInit(); + } + + // + // Getter / Setter (s) ... + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve TimeFrame ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Check Strategy is Disabled or not ... + * + * @return ( bool ) + */ + bool IsDisabled() + { + return mForceDisabled; + } + + /** + * Get Signal Volume ... + * + * @return ( double ) + */ + double Volume() + { + return mVolume; + } + + /** + * Set Signal Volume ... + * + * @param value: Double ... + */ + void Volume(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mVolume = value; + } + + /** + * Get Risk/Reward Ratio ... + * + * @return ( double ) + */ + double R2R() + { + return mR2R; + } + + /** + * Set Risk/Reward Ratio ... + * + * @param value: Double ... + */ + void R2R(double value) + { + // + if (value < 0) + { + value = 1.5; + } + + // + mR2R = value; + } + + /** + * Get Max Allowed Spread ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread ... + * + * @param value: Double ... + */ + void MaxAllowedSpread(double value) + { + mMaxAllowedSpread = value; + } + + /** + * Get Long Signalling State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Long Signalling State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + mAllowLong = value; + } + + /** + * Get Short Signalling State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Short Signalling State ... + * + * @param value: Argument 1 + */ + void AllowShort(bool value) + { + mAllowShort = value; + } + + // + // Actions ... + + /** + * Disable Strategy ... + */ + void Disable() + { + mForceDisabled = true; + } + + /** + * Enable Strategy ... + */ + void Enable() + { + mForceDisabled = false; + } + + /** + * Register Signal Event Handler ... + * + * @param handler: an Instance of TOnXSignal ... + */ + void AddXSignalEventHandler(TOnX121SMCSignal handler) + { + // + Add( + handler, + mSignalEventHandlers // + ); + } + + // + // Virtual Actions ... + + /** + * Destroy All Class Implementations ... + */ + virtual void Destroy() + { + } + + /** + * Handle Tick Processing ... + * + * @param positions: XPosition instance Collection ... + */ + virtual void HandleTick() + { + // + DoUnwaitedTicksWork(); + + // + // Check State ... + if (IsDisabled()) + { + return; + } + + // + // Check Signalling State ... + if (!AllowLong() && !AllowShort()) + { + return; + } + + // + // Check Bar Tracker State ... + if (!mBarTracker.CanProcessBar()) + { + return; + } + + // + // Retrieve Current Tick and Check it's Time + // by Last Issued Tick ... + MqlTick cTick; + bool hasTick = GetTick( + mSymbol, + cTick // + ); + bool isSameAsLast = cTick.time == mLastTick.time; + if (isSameAsLast) + { + return; + } + + // + // Update Last Issued Tick ... + mLastTick = cTick; + + // + // Check Current Processing Tick has Signal or not ... + XSignal signal; + X121SMCStrategyConditions conditions; + bool hasSignal = HasSignal( + signal, + conditions // + ); + if (!hasSignal) + { + return; + } + + // + // Waits Until Next Candle if Current Tick has Signal ... + mBarTracker.Waits(); + + // + // Notify Signal Event Handlers ... + NotifyOnSignalEventHandlers( + signal, + conditions // + ); + } + + /** + * Check for any Guards ... + * + * @param guards: X121SMCGuard instance Collection ... + * @param positions: XPosition instance Collection ... + * + * @return ( virtual bool ) + */ + virtual bool HandleGuard( + X121SMCGuard &guards[], + XPosition &positions[] // + ) + { + // + bool result = false; + + // + // Check State ... + if (IsDisabled()) + { + return result; + } + + // + // Check Signalling State ... + if (!AllowLong() && !AllowShort()) + { + return result; + } + + // + // Check Bar Tracker State ... + if (!mGuardBarTracker.CanProcessBar()) + { + return result; + } + + // + // Check For Guards ... + result = CheckGuard( + guards, + positions // + ); + + // + // Waits Until Next Candle if Current Tick has Guard ... + mGuardBarTracker.Waits(); + + // + Clean(positions); + + // + return result; + } + + /** + * Check For Signal ... + * + * @param signal: XSignal instance ... + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( virtual bool ) + */ + virtual bool HasSignal( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + return result; + } + + /** + * Check for any Guard Actions ... + * + * @param guards: X121SMCGuard instance Collection ... + * + * @return ( virtual bool ) + */ + virtual bool CheckGuard( + X121SMCGuard &guards[], + const XPosition &positions[] // Positions ... + ) + { + // + bool result = false; + + // + return result; + } + + /** + * Update all Requirements without waiting ... + */ + virtual void DoUnwaitedTicksWork() + { + } + + /** + * Detect SL Candidates based on Strategy and Conditions ... + * + * @param result: Double array reference ... + * @param entry: Double, Position Entry Price ... + * @param conditions: X121SMCStrategyConditions instance, Provides Configurations ... + * @param type: ENUM_X_POSITION_TYPES member, Specified Position Type ... + */ + virtual void DetectSLCandidates( + double &result[], + double entry, + X121SMCStrategyConditions &conditions, + ENUM_X_POSITION_TYPES type // + ) + { + } + + /** + * Customize Strategy Identifier ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + + // + // Props ... + + // + MqlTick mLastTick; // Last Issued Tick ... + + // + XBarTracker mBarTracker; // Strategy Bar Tracker ... + XBarTracker mGuardBarTracker; // Strategy Guard Bar Tracker ... + XCBarAnalyser *mBarAnalyser; // Bar Analyser Instance + + // + // Actions ... + + /** + * Prepare and Normalize Signal for Execution in Strategy ... + * + * @param signal: XSignal instance ... + * + * @return ( bool ) + */ + bool PrepareSignal(XSignal &signal) + { + // + bool result = false; + + // + // Check Strategy Is Enables ... + result = !IsDisabled(); + if (!result) + { + return result; + } + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + bool isLong = IsLong(signal.type); + + // + // TODO: Implement Signal Preparation Mechanism here ... + + // + return result; + } + + // + + /** + * Notified Signal Event Handler(s) ... + * + * @param signal: XSignal instance ... + * @param conditions: XStrategyConditions instance ... + */ + void NotifyOnSignalEventHandlers( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + if (!signal.IsValid() || !conditions.IsValid()) + { + return; + } + + // + int count = ArraySize(mSignalEventHandlers); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mSignalEventHandlers[i]( + signal, + conditions // + ); + } + } + + // + // Private ... + private: + // + // Props ... + + // + string mSymbol; // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ... + bool mForceDisabled; // Force Disabled ... + bool mAllowLong; // Allow Long Signals + bool mAllowShort; // Allow Short Signals + double mR2R; // Risk/Rewar Ratio ... + double mVolume; // Static Volume Per Trades ... + + // + double mMaxAllowedSpread; // Max Allowed Spread ... + + // + // On X121 Signal Recieved Event Handler(s) ... + TOnX121SMCSignal mSignalEventHandlers[]; + + // + // Actions ... + + /** + * Install all Helpers and Prepare all Configurations for required Indicators ... + */ + void Init() + { + // + mForceDisabled = false; + + // + R2R(1); + Volume(0.01); + + // + string symbol = Symbol(); + ENUM_TIMEFRAMES period = Period(); + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + symbol, + period // + ); + + // + // Initialize Guard Bar Tracker ... + mGuardBarTracker.Init( + symbol, + period // + ); + + // + mBarAnalyser = new XCBarAnalyser(); + + // + } + + /** + * De Initialize all Tools ... + */ + void DeInit() + { + // + ZeroMemory(mBarAnalyser); + + // + delete mBarAnalyser; + + // + Clean(mSignalEventHandlers); + + // + Destroy(); + } + + /** + * Reste Bar Tracker ... + */ + void ResetBarTracker() + { + mBarTracker.Clean(); + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 new file mode 100644 index 0000000..3f37d87 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../../Classes/x-saherelm.x-cobject.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +enum ENUM_X121SMC_CHARTOBJECTS +{ + X_121_NONE_OBJ +}; + +// +// Implementations ... diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 new file mode 100644 index 0000000..47d16e0 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121Panel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-app-dialog.class.mq5" + +// +// Implementation ... + +// +class X121CAppDialog : public XCAppDialog +{ + // + public: + // + // Constructor(s) ... + void X121CAppDialog() + { + } + + // + // Deconstructor ... + void ~X121CAppDialog() + { + } + + // + void Configure() + { + // + // Configure Dialog ... + BackgroundColor(clrBlack); + } + + // + protected: + // + + // + private: + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.ex5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..661b44771e7e75739b21ad2acde7073812280c57 GIT binary patch literal 16866 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 E1G(cessI20 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 new file mode 100644 index 0000000..da8f365 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 @@ -0,0 +1,1082 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121SMCCycleHelper +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... + +enum ENUM_X_CYCLES +{ + X_CYCLE_NONE, + X_CYCLE_TRIGGER, + X_CYCLE_DECISION, + X_CYCLE_ANALYSE, + X_CYCLE_VERIFICATION, + X_CYCLE_CONSOLIDATION, + X_CYCLE_VISION, +}; + +string ToString(ENUM_X_CYCLES value) +{ + // + string result = EnumToString(value); + + // + StringReplace(result, "X_CYCLE_", ""); + + // + return result; +} + +enum ENUM_X_CYCLE_EVENTS +{ + SAR_CHANGE_DETECTED, + NEW_PEAK_DETECTED, + NEW_VALE_DETECTED, + PIVOT_POINT_DETECTED, + VWAP_ORDER_CHANGE_ETECTED, + VWAP_STATE_CHANGE_DETCTED, + CONSOLIDATION_BREAKED_DETECTED, + PEAK_PIVOT_STARTED, + PEAK_PIVOT_ENDED, + VALE_PIVOT_STARTED, + VALE_PIVOT_ENDED, +}; + +// +class XC121SMCCycleHelper : public XCBase +{ + // + public: + // + // Props ... + + // + // X121 ... + XCX121Helper *mX121Helper; + + // + // POI Detector ... + XCPOIDrawer *mPOIDrawer; + XCPOIDetector *mPOIDetector; + + // + // Bar Analyser + XCBarAnalyser *mBarAnalyser; + + // + // Constructor(s) ... + XC121SMCCycleHelper() + { + Default(); + } + + // + // Deconstructor ... + ~XC121SMCCycleHelper() + { + DeInit(); + } + + // + // Getter/Setter(s) ... + + // + // Actions ... + + /** + * Initialize ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + * @param x121Inputs: X121Inputs instance ... + * + * @return ( bool ) + */ + bool Init( + string symbol, + ENUM_TIMEFRAMES period, + X121Inputs &x121Inputs, + int requiredPOIs = 50 // + ) + { + // + bool result = false; + + // + if (requiredPOIs < 0) + { + requiredPOIs = 0; + } + + // + result = IsValid(symbol) && + IsValid(period); + if (!result) + { + return result; + } + + // + mSymbol = symbol; + mPeriod = period; + + // + // X121 ... + mX121Helper = new XCX121Helper(); + result = mX121Helper.Init( + symbol, + period, + x121Inputs // + ); + if (!result) + { + return result; + } + + // + mPOIDetector = new XCPOIDetector( + symbol, + period // + ); + mPOIDetector.MaxRequiredPOIs(requiredPOIs); + + // + int maxLoopbackBars = mPOIDetector.MaxAllowedLoopbackForInit(); + int periodSeconds = PeriodSeconds(period); + if (periodSeconds > PeriodSeconds(PERIOD_M15)) + { + // + int multiplier = periodSeconds / PeriodSeconds(PERIOD_M15); + + // + if (multiplier >= 1) + { + maxLoopbackBars *= 2; + } + } + mPOIDetector.MaxAllowedLoopbackForInit(maxLoopbackBars); + mPOIDetector.Init(); + + // + // Initialize Bar Analyser Class Instance ... + mBarAnalyser = new XCBarAnalyser(); + + // + // Initial and Configure POI Drawer if Required ... + mPOIDrawer = new XCPOIDrawer(); + mPOIDrawer.ChartIdentification(0); + mPOIDrawer.SubWindowIdentification(0); + + // + mPOIDrawer.DemandZoneFill(false); + mPOIDrawer.SupplyZoneFill(false); + mPOIDrawer.BullishFVGFill(false); + mPOIDrawer.BearishFVGFill(false); + mPOIDrawer.SupportZoneFill(false); + mPOIDrawer.ResistanceZoneFill(false); + mPOIDrawer.BullishOrderBlockFill(false); + mPOIDrawer.BearishOrderBlockFill(false); + + // + // Set Chart Style ... + ApplyChartStyle(); + + // + return result; + } + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve TimeFrame (Period) ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Get Specified Bar ... + * + * @param source: XOHCL instance, Source Bar ... + * @param bar: XOHCL instance, Dest Bar ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &source, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = + IsValid(symbol) && + IsValid(period) && + source.IsValid(); + if (!result) + { + return result; + } + + // + int index = iBarShift( + symbol, + period, + source.time // + ); + result = bar.Init( + symbol, + period, + index // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (index < 0) + { + index = 0; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param time: Datetime ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + int index = GetBarIndex(time); + result = GetBar(bar, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Time Bar Index ... + * + * @param time: DateTime ... + * + * @return ( int ) + */ + int GetBarIndex(datetime time = NULL) + { + // + int result = -1; + + // + time = NormalizeTime(time); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = iBarShift( + symbol, + period, + time // + ); + + // + return result; + } + + /** + * Retrieve Cycle Conditions ... + * + * @param events: ENUM_X_CYCLE_EVENTS member, Array ... + * @param conditions: X121SMCCycleConditions instance ... + * @param barIndex: Integer ... + * @param loopback: Integer ... + * + * @return ( bool ) + */ + bool GetConditions( + ENUM_X_CYCLE_EVENTS &events[], + ENUM_XPOI_EVENTS &poiEvents[], + X121SMCCycleConditions &conditions, + int barIndex = 0, + int loopback = 7 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 5) + { + loopback = 5; + } + + // + Clean(events); + Clean(poiEvents); + conditions.Clean(); + + // + result = mX121Helper.GetConditions( + conditions.x121Conditions, + barIndex, + loopback // + ); + if (!result) + { + // + conditions.Clean(); + return result; + } + + // + mPOIDetector.Update(poiEvents); + mPOIDetector.GetState(conditions.state); + + // + conditions.symbol = GetSymbol(); + conditions.period = GetPeriod(); + conditions.time = TimeCurrent(); + + // + // Update(); + + // + result = conditions.IsValid(); + + // + return result; + } + + bool GeneratePVBox( + XBoxZone &box, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + box.Clean(); + box.symbol = GetSymbol(); + box.period = GetPeriod(); + + // + int index = barIndex; + + // + // Peak ... + datetime peaksSameFrom = NULL; + double peak = mX121Helper.xpvHelper.GetPeak(index); + double prevPeak = mX121Helper.xpvHelper.GetPeak(index + 1); + bool startsByPeak = peak == prevPeak; + + // + // Vale ... + datetime valesSameFrom = NULL; + double vale = mX121Helper.xpvHelper.GetVale(index); + double prevVale = mX121Helper.xpvHelper.GetVale(index + 1); + bool startsByVale = vale == prevVale; + + // + bool canBreak = false; + while (!canBreak) + { + // + index++; + + // + datetime cTime = iTime( + box.symbol, + box.period, + index // + ); + + // + // Peak ... + double iPeak = mX121Helper.xpvHelper.GetPeak(index); + + // + // Vale ... + double iVale = mX121Helper.xpvHelper.GetVale(index); + + // + // Start By Peak or Value ... + bool isSame = false; + if (startsByPeak) + { + // + isSame = iPeak == peak; + bool canSetVale = vale == 0 + ? true + : iVale > vale; + if (canSetVale) + { + vale = iVale; + } + } + else if (startsByVale) + { + // + isSame = iVale == vale; + bool canSetPeak = peak == 0 + ? true + : iPeak < peak; + if (canSetPeak) + { + peak = iPeak; + } + } + + // + if (isSame) + { + // + box.from = cTime; + box.upper = peak; + box.lower = vale; + } + else if (IsValid(box.from)) + { + // + // Complete Box ... + box.to = iTime( + box.symbol, + box.period, + barIndex // + ); + + // + box.type = "XPVBox"; + box.dir = startsByPeak + ? X_DIRECTION_BEARISH + : startsByVale + ? X_DIRECTION_BULLISH + : X_DIRECTION_NONE; + } + + // + canBreak = !isSame; + } + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; + } + + // + // Virtuals ... + + /** + * Set Default Properties Values ... + */ + virtual void Default() + { + } + + // + protected: + // + + // + private: + // + // Props ... + string mSymbol; + ENUM_TIMEFRAMES mPeriod; + + // + // Actions ... + + /** + * Release All Resources ... + */ + void DeInit() + { + // + ZeroMemory(mX121Helper); + ZeroMemory(mPOIDetector); + ZeroMemory(mBarAnalyser); + + // + delete mX121Helper; + delete mPOIDetector; + delete mBarAnalyser; + } + + /** + * Apply Chart Style ... + */ + void ApplyChartStyle() + { + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + + // + ENUM_CHART_MODE mMode = CHART_CANDLES; // chart's mMode + bool mShowBidLine = true; // show bid line + bool mShowAskLine = true; // show ask line + bool mShowGrid = false; // show grids on chart + bool mShowVolumes = false; // show volumes + bool mShowTradeLevels = true; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true; // chart autoscroll + bool mQuickNavigation = true; // chart quick navigation state + color mForeGroundColor = clrWhite; // chart's foreground color + color mBackGroundColor = clrBlack; // chart's background color + color mUpColor = clrGreen; // Up Color + color mDownColor = clrRed; // Down Color + color mBullishColor = clrGreen; // Bullish color + color mBearishColor = clrRed; // Bearish color + color mGridColor = clrGray; // grid color + color mBidLineColor = clrGray; // bid line color + color mAskLineColor = clrRed; // ask line color + color mLineColor = clrLime; // line mMode and doji candlestick color + color mStopColor = clrGold; // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen; // volumes color + + // + ChartSetInteger(chartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(chartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(chartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(chartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(chartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(chartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(chartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(chartId, CHART_COLOR_VOLUME, mVolumesColor); + + // + // For Enabling XCC ... + // ChartSetInteger(chartId, CHART_MODE, mMode); + // ChartSetInteger(chartId, CHART_COLOR_CHART_UP, mUpColor); + // ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, mDownColor); + // ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + // ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + // ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, mLineColor); + } + + // +}; + +// +struct X121SMCStrategySignalProviderData +{ + // + // Props ... + + // + // Decision ... + XPOIState decisionState; + double decisionBullishScore; + double decisionBearishScore; + X121Conditions decisionXConditions; + ENUM_XPOI_EVENTS decisionPoiEvents[]; + XC121SMCCycleHelper *decisionCycleHelper; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + + // + // Analyse ... + XPOIState analyseState; + double analyseBullishScore; + double analyseBearishScore; + X121Conditions analyseXConditions; + ENUM_XPOI_EVENTS analysePoiEvents[]; + XC121SMCCycleHelper *analyseCycleHelper; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + + // + // Consolidation ... + XPOIState consolidationState; + double consolidationBullishScore; + double consolidationBearishScore; + X121Conditions consolidationXConditions; + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + XC121SMCCycleHelper *consolidationCycleHelper; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + + // + // Vision ... + XPOIState visionState; + double visionBullishScore; + double visionBearishScore; + X121Conditions visionXConditions; + ENUM_XPOI_EVENTS visionPoiEvents[]; + XC121SMCCycleHelper *visionCycleHelper; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + + // + // Constructor ... + X121SMCStrategySignalProviderData() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + // Decision ... + decisionState.Clean(); + decisionBullishScore = 0; + decisionBearishScore = 0; + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + decisionConditions.Clean(); + decisionXConditions.Clean(); + + // + // Analyse ... + analyseState.Clean(); + analyseBullishScore = 0; + analyseBearishScore = 0; + Clean(analysePoiEvents); + Clean(analyseCycleEvents); + analyseConditions.Clean(); + analyseXConditions.Clean(); + + // + // Consolidation ... + consolidationState.Clean(); + consolidationBullishScore = 0; + consolidationBearishScore = 0; + Clean(consolidationPoiEvents); + Clean(consolidationCycleEvents); + consolidationConditions.Clean(); + consolidationXConditions.Clean(); + + // + // Vision ... + visionState.Clean(); + visionBullishScore = 0; + visionBearishScore = 0; + Clean(visionPoiEvents); + Clean(visionCycleEvents); + visionConditions.Clean(); + visionXConditions.Clean(); + } + + // + void Destroy() + { + // + Clean(); + + // + ZeroMemory(decisionCycleHelper); + ZeroMemory(analyseCycleHelper); + ZeroMemory(consolidationCycleHelper); + ZeroMemory(visionCycleHelper); + + // + ZeroMemory(this); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + visionCycleHelper != NULL && + analyseCycleHelper != NULL && + decisionCycleHelper != NULL && + consolidationCycleHelper != NULL; + + // + return result; + } + + // + // Initialize ... + bool Init( + XC121SMCCycleHelper *_decisionCycleHelper, + XC121SMCCycleHelper *_analyseCycleHelper, + XC121SMCCycleHelper *_consolidationCycleHelper, + XC121SMCCycleHelper *_visionCycleHelper // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = + // + _visionCycleHelper != NULL && + _analyseCycleHelper != NULL && + _decisionCycleHelper != NULL && + _consolidationCycleHelper != NULL + // + ; + if (!result) + { + return result; + } + + // + visionCycleHelper = _visionCycleHelper; + analyseCycleHelper = _analyseCycleHelper; + decisionCycleHelper = _decisionCycleHelper; + consolidationCycleHelper = _consolidationCycleHelper; + + // + result = IsValid(); + + // + return result; + } + + // + // Prepare all ... + bool Prepare( + int barIndex = 0, + int loopback = 10 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 7) + { + loopback = 7; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + // Decision ... + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + barIndex, + loopback // + ); + if (!result) + { + // + Clean(decisionPoiEvents); + Clean(decisionCycleEvents); + + // + decisionConditions.Clean(); + + // + return result; + } + + // + // Analyse ... + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + barIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + + // + return result; + } + + // + // Consolidation ... + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + barIndex, + loopback // + ); + if (!result) + { + // + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + return result; + } + + // + // Vision ... + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + barIndex, + loopback // + ); + if (!result) + { + // + Clean(visionPoiEvents); + Clean(analysePoiEvents); + Clean(decisionPoiEvents); + Clean(consolidationPoiEvents); + + // + Clean(visionCycleEvents); + Clean(analyseCycleEvents); + Clean(decisionCycleEvents); + Clean(consolidationCycleEvents); + + // + visionConditions.Clean(); + analyseConditions.Clean(); + decisionConditions.Clean(); + consolidationConditions.Clean(); + + // + return result; + } + + // + // Cycles POI States ... + decisionState = decisionConditions.state; + analyseState = analyseConditions.state; + consolidationState = consolidationConditions.state; + visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + decisionXConditions = decisionConditions.x121Conditions; + analyseXConditions = analyseConditions.x121Conditions; + consolidationXConditions = consolidationConditions.x121Conditions; + visionXConditions = visionConditions.x121Conditions; + + // + // Decision ... + decisionXConditions.GenerateScore( + decisionBullishScore, + decisionBearishScore // + ); + + // + // Analyse ... + analyseXConditions.GenerateScore( + analyseBullishScore, + analyseBearishScore // + ); + + // + // Consolidation ... + consolidationXConditions.GenerateScore( + consolidationBullishScore, + consolidationBearishScore // + ); + + // + // Vision ... + visionXConditions.GenerateScore( + visionBullishScore, + visionBearishScore // + ); + + // + return result; + } + + // + void MaxRequiredPOIs(int value) + { + // + if (!IsValid()) + { + return; + } + + // + visionCycleHelper.mPOIDetector.MaxRequiredPOIs(value); + analyseCycleHelper.mPOIDetector.MaxRequiredPOIs(value); + decisionCycleHelper.mPOIDetector.MaxRequiredPOIs(value); + consolidationCycleHelper.mPOIDetector.MaxRequiredPOIs(value); + } + + // + void MaxAllowedLoopbackForInit(int value) + { + // + if (!IsValid()) + { + return; + } + + // + visionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(value); + analyseCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(value); + decisionCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(value); + consolidationCycleHelper.mPOIDetector.MaxAllowedLoopbackForInit(value); + } + + // +}; diff --git a/BKPS/14031218/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 new file mode 100644 index 0000000..cae1bce --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 @@ -0,0 +1,4400 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCX121SMCTradeHandler +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +// +// Model a Trade Data ... +struct X121SMCTradeData +{ + // + double ask; // Ask Price on Start Time + double bid; // bid Price on Start Time + ulong ticket; // Position Ticket + double swap; // Swap + double profit; // Profit on Close + XSignal signal; // Signal Object + string message; // Message + datetime endTime; // End Time + datetime startTime; // Start Time + double commission; // Commission + string conditions; // Signal Conditions + double maxDrawdown; // Max Position Drawdown + double lastTarget; // Check Last Targetted + double lastTrailedTPLevel; // Hold Last Trailed TP Level + + // + // Constructor ... + X121SMCTradeData() + { + Clean(); + } + + /** + * Initialize Item ... + * + * @param _signal: XSignal instance Reference, Provides Source For Initializaion ... + * + * @return ( bool ) + */ + bool Init(XSignal &_signal) + { + // + bool result = false; + + // + Clean(); + + // + result = _signal.IsValid(); + if (!result) + { + return result; + } + + // + signal = _signal; + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + /** + * Cleaning Up Model ... + */ + void Clean() + { + // + ask = 0; + bid = 0; + swap = 0; + profit = 0; + ticket = 0; + commission = 0; + maxDrawdown = 0; + lastTrailedTPLevel = 0; + + // + endTime = NULL; + message = NULL; + startTime = NULL; + conditions = NULL; + + // + lastTarget = 0; + + // + signal.Clean(); + + // + ZeroMemory(this); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + signal.IsValid() + // + ; + + // + return result; + } + + /** + * Calculate Model Age ... + * + * @return ( int ) + */ + int GetAge() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + int startIndex = iBarShift( + GetSymbol(), + GetPeriod(), + startTime, + false // + ); + + // + datetime mEndTime = IsValid(endTime) + ? endTime + : TimeCurrent(); + int endIndex = iBarShift( + GetSymbol(), + GetPeriod(), + mEndTime, + false // + ); + + // + result = MathAbs(startIndex - endIndex); + + // + return result; + } + + // + // Owner Functions ... + + /** + * Check a Ticket is Own to Model or not ... + * + * @param _ticket: ULONG, Position Ticket ... + * + * @return ( bool ) + */ + bool IsOwn( + ulong _ticket // + ) + { + // + bool result = false; + + // + result = IsValid() && + _ticket == ticket; + + // + return result; + } + + /** + * Check Specified Conditions is Own to Model or not ... + * + * @param _symbol: String, Specified Symbol ... + * @param _provider: String, Specified Provider ... + * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... + * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... + * + * @return ( bool ) + */ + bool IsOwnSignalTime( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type, + datetime _time // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_time) && + Time() == _time && + IsValid(_symbol) && + IsValid(_period) && + XType() == _type && + IsValid(_provider) && + GetPeriod() == _period && + GetSymbol() == _symbol && + Provider() == _provider && + XType() != X_POSITION_TYPE_ALL && + XType() != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + /** + * Check Specified Conditions is Own to Model or not ... + * + * @param _symbol: String, Specified Symbol ... + * @param _provider: String, Specified Provider ... + * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... + * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... + * + * @return ( bool ) + */ + bool IsOwnStartTime( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type, + datetime _time // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_time) && + IsValid(_symbol) && + IsValid(_period) && + XType() == _type && + IsValid(startTime) && + startTime == _time && + IsValid(_provider) && + GetPeriod() == _period && + GetSymbol() == _symbol && + Provider() == _provider && + XType() != X_POSITION_TYPE_ALL && + XType() != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + /** + * Check Specified Signal is Own to Model or not ... + * + * @param _signal: XSignal instance Reference ... + * + * @return ( bool ) + */ + bool IsOwn(XSignal &_signal) + { + // + bool result = false; + + // + result = + // + IsValid() && + _signal.IsValid() && + IsOwnSignalTime( + _signal.symbol, + _signal.provider, + _signal.period, + ToPositionType(_signal.type), + _signal.time) + // + ; + + // + return result; + } + + /** + * Check Specified Position is Own to Model or not ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool IsOwn(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwnStartTime( + _position.symbol, + _position.provider, + _position.period, + ToPositionType(_position.type), + _position.openAt) + // + ; + + // + return result; + } + + /** + * Check Specified Position is Own to Model or not ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool IsOwnPosition(XPosition &_position) + { + // + bool result = false; + + // + double tp = TP(); + double sl = SL(); + double entry = Entry(); + double volume = Volume(); + string symbol = GetSymbol(); + string provider = Provider(); + ENUM_POSITION_TYPE type = Type(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + double pVolume = _position.volume; + double pSL = NormalizePrice(_position.sl, _position.symbol); + double pTP = NormalizePrice(_position.tp, _position.symbol); + double pEntry = NormalizePrice(_position.entry, _position.symbol); + + // + result = + // + IsValid() && + (sl == pSL || + tp == pTP) && + entry == pEntry && + pVolume == volume && + _position.IsValid() && + type == _position.type && + symbol == _position.symbol && + period == _position.period && + provider == _position.provider + // + ; + + // + if (!result) + { + // + result = + // + IsValid() && + _position.IsValid() && + _position.ticket == signal.positionId; + } + + // + return result; + } + + /** + * Update Model Data by Providing Specified Signal ... + * + * @param _signal: XSignal instance Reference ... + * + * @return ( bool ) + */ + bool Update(XSignal &_signal) + { + // + bool result = false; + + // + result = + // + IsValid() && + _signal.IsValid() && + IsOwn(_signal) + // + ; + if (!result) + { + return result; + } + + // + signal = _signal; + + // + return result; + } + + /** + * Update Model Data by Providing Specified Position ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool Update(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwn(_position) + // + ; + if (!result) + { + return result; + } + + // + swap = _position.swap; + ticket = _position.ticket; + profit = _position.profit; + message = _position.comment; + startTime = _position.openAt; + + // + // Set Once ... + if (commission == 0 && + _position.commission != 0) + { + commission = _position.commission; + } + + // + // Set Once ... + if (ask == 0) + { + ask = GetAsk(_position.symbol); + } + + // + // Set Once ... + if (bid == 0) + { + bid = GetBid(_position.symbol); + } + + // + if (profit < 0 && profit < maxDrawdown) + { + maxDrawdown = profit; + } + + // + return result; + } + + /** + * Update Model Data by Providing Specified Position ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool UpdatePosition(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwnPosition(_position) + // + ; + if (!result) + { + return result; + } + + // + swap = _position.swap; + ticket = _position.ticket; + profit = _position.profit; + message = _position.comment; + startTime = _position.openAt; + + // + // Set Once ... + if (commission == 0 && + _position.commission != 0) + { + commission = _position.commission; + } + + // + // Set Once ... + if (ask == 0) + { + ask = GetAsk(_position.symbol); + } + + // + // Set Once ... + if (bid == 0) + { + bid = GetBid(_position.symbol); + } + + // + if (profit < 0 && profit < maxDrawdown) + { + maxDrawdown = profit; + } + + // + return result; + } + + // + // Tools Extensions ... + + /** + * Get Model Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return signal.symbol; + } + + /** + * Get Model Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return signal.period; + } + + /** + * Get Model Provider ... + * + * @return ( string ) + */ + string Provider() + { + return signal.provider; + } + + /** + * Get Model Entry ... + * + * @return ( double ) + */ + double Entry() + { + return signal.entry; + } + + /** + * Get Model Stop Loss ... + * + * @return ( double ) + */ + double SL() + { + return signal.sl; + } + + /** + * Get Model Take Profit ... + * + * @return ( double ) + */ + double TP() + { + return signal.tp; + } + + /** + * Get Model Target ... + * + * @return ( double ) + */ + int Targets(double &targets[]) + { + // + int result = 0; + + // + Copy( + signal.targets, + targets // + ); + + // + result = ArraySize(targets); + + // + return result; + } + + /** + * Get Position Spread on Open Time ... + * + * @return ( double ) + */ + double Spread() + { + return MathAbs(ask - bid); + } + + /** + * Get Model Volume ... + * + * @return ( double ) + */ + double Volume() + { + return signal.volume; + } + + /** + * Get Model Point Value ... + * + * @return ( double ) + */ + double Points() + { + return GetPoints(GetSymbol()); + } + + /** + * Get Model Type ... + * + * @return ( ENUM_POSITION_TYPE ) + */ + ENUM_POSITION_TYPE Type() + { + return signal.type; + } + + /** + * Get Model Type ... + * + * @return ( ENUM_X_POSITION_TYPES ) + */ + ENUM_X_POSITION_TYPES XType() + { + // + ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsLong(Type()) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; + } + + /** + * Get Model Signal Mode ... + * + * @return ( ENUM_X_ORDER_MODES ) + */ + ENUM_X_ORDER_MODES Mode() + { + return signal.mode; + } + + /** + * Get Model Signal Time ... + * + * @return ( datetime ) + */ + datetime Time() + { + return signal.time; + } + + // + // Additional Helpers Extensions ... + + /** + * Get Signal Full TP Level ... + * + * @return ( double ) + */ + double FullTPLevel() + { + return signal.fullTPLevel; + } + + /** + * Check Can Partial Close Position or not ... + * + * @return ( bool ) + */ + bool CanPartialClose() + { + return signal.CanPartialClose(); + } + + /** + * Retrieve Partial Close Volume Multiplier ... + * + * @return ( double ) + */ + double PartialCloseMultiplier() + { + return signal.partialCloseMultiplier; + } + + /** + * Get Partial Close On TP Level ... + * + * @return ( double ) + */ + double PartialCloseOnTPLevel() + { + return signal.partialCloseOnTPLevel; + } + + /** + * Check Can Risk Free Position on Break Even Point or not ... + * + * @return ( bool ) + */ + bool CanRiskFreeOnBreakEvenPoint() + { + return signal.CanRiskFreeOnBreakEvenPoint(); + } + + /** + * Get Minimum Required Profit after Break Even Point for Risk Free ... + * + * @return ( double ) + */ + double TPLevelForBreakEven() + { + return signal.tpLevelForBreakEven; + } + + /** + * Calculate Break Even Point ... + * + * @return ( double ) + */ + double CalculateBreakEvenPoint() + { + // + double result = 0; + + // + bool isValid = + // + ask > 0 && + bid > 0 && + IsValid() && + ticket > 0 && + signal.IsValid() + // + ; + if (!isValid) + { + return result; + } + + // + // Calculate Spread ... + double spread = Spread(); + if (spread <= 0) + { + return result; + } + + // + // Calculate BEP ... + result = + // + spread + (-1 * swap) + MathAbs(commission) + // + ; + + // + return result; + } + + /** + * Check Can Trail Position Stop Loss or not ... + * + * @return ( bool ) + */ + bool CanTrailSL() + { + return signal.CanTrailSL(); + } + + /** + * Get Start Position SL Trailling on TP Level ... + * + * @return ( double ) + */ + double TrailSLStartOnReachTPLevel() + { + return signal.trailSLStartOnReachTPLevel; + } + + // + // Data Collector Extensions ... + + /** + * Get Data Collection File Name ... + * + * @return ( string ) + */ + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetSymbol() + "\\" + + ToString(XType()) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(ticket) + "_" + + ToString(GetPeriod()) + "_" + + ToFormatString(startTime) + // + ; + + // + return result; + } + + /** + * Get Signal Collectiong File Name ... + * + * @return ( string ) + */ + string GetSignalFileName() + { + // + string result = NULL; + + // + result = + // + GetSymbol() + "\\" + + ToString(XType()) + "\\" + + Provider() + "_" + + ToFormatString(startTime) + // + ; + + // + return result; + } + + /** + * Converts Model to String Representation ... + * + * @param onlySignals: Boolean, Specified Represent Only Signal or not ... + * + * @return ( string ) + */ + string ToString( + bool onlySignals = false // + ) + { + // + string result = NULL; + + // + int age = GetAge(); + + // + result = + // + (onlySignals ? "" : ToString("Ticket", ticket)) + + ToString("Symbol", GetSymbol()) + + ToString("Period", GetPeriod()) + + ToString("Entry", Entry()) + + ToString("Provider", Provider()) + + ToString("Type", ToString(XType())) + + ToString("Time", startTime) + + // + // Attach Trade Info ... + (onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Volume", Volume()) + + ToString("Profit", profit) + + ToString("Commission", commission) + + ToString("Swap", swap) + + ToString("Max Drawdown", maxDrawdown) + + ToString("End Time", endTime) + + ToString("Age", age) + + ToString("Message", message) + + "" + // + ) + + // + // Attach Conditions to Signals ... + (!onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Pushers", signal.pushers) + + "Conditions:" + "\n" + + "-------------" + "\n" + + conditions + + "" + // + ) + + // + "" + // + ; + + // + return result; + } + + // + // End Of X121SMCTradeData Model ... +}; + +// +// Model Specified Symbol's Positions States ... +struct X121SMCSymbolPositionInfo +{ + // + string symbol; + + // + datetime enableAt; + + // + int longSLs; + int longTPs; + + // + int shortSLs; + int shortTPs; + + // + int countedSLs; + + // + // Constructor ... + X121SMCSymbolPositionInfo() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + longSLs = 0; + longTPs = 0; + + // + shortSLs = 0; + shortTPs = 0; + + // + countedSLs = 0; + + // + enableAt = NULL; + + // + ZeroMemory(this); + } + + /** + * Check is own Symbol Info ... + * + * @param _symbol: String ... + * + * @return ( bool ) + */ + bool IsOwn(string _symbol) + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + _symbol == symbol + // + ; + + // + return result; + } + + /** + * Check Symbol Trading is Enable or not ... + * + * @param time: DateTime ... + * + * @return ( bool ) + */ + bool IsEnable(datetime time = NULL) + { + // + bool result = false; + + // + time = NormalizeTime(time); + + // + bool isEnableAtValid = IsValid(enableAt); + + // + result = + !isEnableAtValid + ? true + : time > enableAt; + if (result && + isEnableAtValid) + { + Reset(); + } + + // + return result; + } + + /** + * Pause Symbol Trading ... + * + * @param seconds: Integer ... + */ + void Pause(int seconds) + { + // + if (seconds <= 0) + { + return; + } + + // + datetime _enableAt = ((datetime)((int)TimeCurrent() + seconds)); + enableAt = _enableAt; + } + + /** + * Handle Stop Loss ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleSL(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longSLs++; + } + else + { + shortSLs++; + } + + // + countedSLs++; + } + + /** + * Handle Take Profit ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleTP(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longTPs++; + } + else + { + shortTPs++; + } + + // + countedSLs--; + if (countedSLs < 0) + { + countedSLs = 0; + } + } + + /** + * Reset Counter ... + */ + void Reset() + { + // + countedSLs = 0; + enableAt = NULL; + } + + // + // End of X121SMCSymbolPositionInfo Model ... +}; + +// +// Implementations ... + +// +// a Class For Read and Write Trade Info Data in Files ... +class X121SMCTradeCollector +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor(s) ... + X121SMCTradeCollector( + string _path = NULL // Base Path + ) + { + // + mAccount = new XCAccount(); + + // + if (IsValid(_path)) + { + mPath = _path; + } + else + { + mPath = "X121SMCTradeData" + "\\" + mAccount.GetCompany(); + } + } + + // + // Deconstructor ... + ~X121SMCTradeCollector() + { + } + + /** + * Check Specified Model is Exists or not ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool IsExists(X121SMCTradeData &item) + { + // + bool result = false; + + // + int mHandler = GetFileHandlerForRead(item); + result = mHandler != INVALID_HANDLE; + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model as Data ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool Save(X121SMCTradeData &item) + { + // + bool result = false; + + // + // Check info is Valid ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true); + + // + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model as Signal ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool SaveSignal(X121SMCTradeData &item) + { + // + bool result = false; + + // + string content = item.ToString(true); + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetSignalFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model Conditions ... + * Conditions only save for Loss Signals ... + * this means the profit must be Lower than Zero ... + * ans also message Contains SL ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool SaveConditions(X121SMCTradeData &item) + { + // + bool result = false; + + // + // Validate Item ... + result = + // + item.profit < 0 && + Contains("SL", item.message) + // + ; + if (!result) + { + return result; + } + + // + string content = item.signal.conditions; + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetConditionsFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mHandler, 0, SEEK_END); + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + string mPath; // Base Path ... + + // + XCAccount *mAccount; + + // + string GetFilePath(X121SMCTradeData &item) + { + // + string fileName = item.GetFileName(); + + // + return GetFilePath(fileName); + } + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetSignalFilePath(X121SMCTradeData &item) + { + // + string fileName = item.GetSignalFileName(); + + // + return GetSignalFilePath(fileName); + } + string GetSignalFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetConditionsFilePath(X121SMCTradeData &item) + { + // + bool isLong = IsLong(item.Type()); + + // + string fileName = + item.GetSymbol() + "\\" + + (isLong ? "Longs" : "Shorts"); + + // + return GetConditionsFilePath(fileName); + } + string GetConditionsFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + int GetFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetSignalFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetSignalFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetConditionsFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetConditionsFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + // End of X121SMCTradeCollector Class ... +}; + +// +// Trade Handler Class ... +// a Class For Handling All Trade Requirements ... +class XC121SMCTradeHandler : public XCBaseAlert +{ + // + // Public ... + public: + // + + // + // Constructor(s) ... + XC121SMCTradeHandler(XCTrade *trader) + { + // + mTrader = trader; + mAdditionalVolume = 0; + mCollector = new X121SMCTradeCollector(); + } + + // + // Deconstructor ... + ~XC121SMCTradeHandler() + { + // + Clean(mData); + Clean(mSymbolInfos); + Clean(mLastExecutedSignals); + + // + delete mTrader; + delete mCollector; + } + + // + // ReadOnly Props ... + + /** + * Get Max Same Time Trades ... + * + * @return ( double ) + */ + double GetMaxSameTimeTrades() + { + return maxSameTimeTrades; + } + + /** + * Get Max Drawdown Happens ... + * + * @return ( double ) + */ + double GetMaxDrawdown() + { + return maxDrawdown; + } + + /** + * Get Currently Drawdown of Account ... + * + * @return ( double ) + */ + double GetCurrentDrawdown() + { + return currentDrawdown; + } + + /** + * Get Account Current Drawdown Percent ... + * + * @return ( double ) + */ + double GetDrawdownPercent() + { + return drawdownPercent; + } + + // + // Properties Getter(s) / Setter(s) ... + + // + // Saving Properties ... + + /** + * Get Save Signals State ... + * + * @return ( bool ) + */ + bool SaveSignals() + { + return mSaveSignals; + } + + /** + * Set Save Signals State ... + * + * @param value: Boolean ... + */ + void SaveSignals(bool value) + { + mSaveSignals = value; + } + + /** + * Get Save Trades State ... + * + * @return ( bool ) + */ + bool SaveTrades() + { + return mSaveTrades; + } + + /** + * Set Save Trades State ... + * + * @param value: Boolean ... + */ + void SaveTrades(bool value) + { + mSaveTrades = value; + } + + /** + * Get Save Conditions State ... + * + * @return ( bool ) + */ + bool SaveConditions() + { + return mSaveConditions; + } + + /** + * Set Save Conditions State ... + * + * @param value: Boolean ... + */ + void SaveConditions(bool value) + { + mSaveConditions = value; + } + + // + // Signalling Props ... + + /** + * Get Allow Long Signals State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + mAllowLong = value; + } + + /** + * Get Allow Short Signals State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signals State ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + mAllowShort = value; + } + + /** + * Get Max Allowed Long Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedLongs() + { + return mMaxAllowedLongs; + } + + /** + * Set Max Allowed Long Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedLongs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedLongs = value; + } + + /** + * Get Max Allowed Short Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedShorts() + { + return mMaxAllowedShorts; + } + + /** + * Set Max Allowed Short Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedShorts(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedShorts = value; + } + + /** + * Get Use Max Allowed Signal Types Per Symbol State ... + * + * @return ( bool ) + */ + bool UseMaxAllowedSignalsPerSymbol() + { + return mUseMaxAllowedSignalsPerSymbol; + } + + /** + * Set Use Max Allowed Signal Types Per Symbol State ... + * + * @param value: Boolean ... + */ + void UseMaxAllowedSignalsPerSymbol(bool value) + { + mUseMaxAllowedSignalsPerSymbol = false; + } + + /** + * Get Last Position Profit In Points for Accept new Signal ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double LastPositionProfitForAcceptNextInPoint() + { + return mLastPositionProfitForAcceptNextInPoint; + } + + /** + * Set Last Position Profit In Points for Accept new Signal ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void LastPositionProfitForAcceptNextInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mLastPositionProfitForAcceptNextInPoint = value; + } + + /** + * Get Delay between two Signals in Bars ... + * 0 => Accept All ... + * + * @return ( int ) + */ + int DelaysBetweenTwoSignalsInBar() + { + return mDelaysBetweenTwoSignalsInBar; + } + + /** + * Set Delay between two Signals in Bars ... + * + * @param value: Integer ... + * 0 => Accept All ... + */ + void DelaysBetweenTwoSignalsInBar(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelaysBetweenTwoSignalsInBar = value; + } + + /** + * Get Max Allowed Spread for Signalling ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread for Signalling ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void MaxAllowedSpread(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSpread = value; + } + + /** + * Get Additional Signal Volume ... + * + * @return ( double ) + */ + double AdditionalVolume() + { + return mAdditionalVolume; + } + + /** + * Set Additional Signal Volume ... + * + * @param value: Double ... + * min = 0.01 + */ + void AdditionalVolume(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + mAdditionalVolume = value; + } + + // + // Risk Management Props ... + + /** + * Get Max Allowed Drawdown Percent for Open Trades ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + * + * @return ( double ) + */ + double MaxAllowedDrawdownToOpenTrades() + { + return mMaxAllowedDrawdownToOpenTrades; + } + + /** + * Set Max Allowed Drawdown Percent for Open Trades ... + * + * @param value: Double ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + */ + void MaxAllowedDrawdownToOpenTrades(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 50) + { + value = 50; + } + + // + mMaxAllowedDrawdownToOpenTrades = value; + } + + /** + * Get Max Allowed SL for Pause Signalling Per Symbol ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedSLToPauseSignallingPerSymbol() + { + return mMaxAllowedSLToPauseSignallingPerSymbol; + } + + /** + * Set Max Allowed SL for Pause Signalling Per Symbol ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedSLToPauseSignallingPerSymbol(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLToPauseSignallingPerSymbol = value; + } + + /** + * Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int PauseSignallingAfterReachesMaxAllowedSLInSecconds() + { + return mPauseSignallingAfterReachesMaxAllowedSLInSecconds; + } + + /** + * Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value; + } + + // + // Protection Props ... + + /** + * Get Allow Hedge Positions State ... + * + * @return ( bool ) + */ + bool AllowHedging() + { + return mAllowHedging; + } + + /** + * Set Allow Hedge Positions State ... + * + * @param value: Boolean ... + */ + void AllowHedging(bool value) + { + mAllowHedging = value; + } + + /** + * Get Minimum Open Positions for Hedging ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinOpenTradesFroHedging() + { + return mMinOpenTradesFroHedging; + } + + /** + * Set Minimum Open Positions for Hedging ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinOpenTradesFroHedging(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinOpenTradesFroHedging = value; + } + + /** + * Get Minimum Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgingMinVolumeStep() + { + return mHedgingMinVolumeStep; + } + + /** + * Set Minimum Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgingMinVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + if (value > 0 && value > 0.1) + { + value = 0.1; + } + + // + mHedgingMinVolumeStep = value; + } + + /** + * Get Minimum Required Profit Per Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgeingMinRequiredProfitPerVolumeStep() + { + return mHedgeingMinRequiredProfitPerVolumeStep; + } + + /** + * Set Minimum Required Profit Per Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgeingMinRequiredProfitPerVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mHedgeingMinRequiredProfitPerVolumeStep = value; + } + + // + // Actions ... + + // + // Data Collection Actions ... + + /** + * Add Executed Signal Data Model to Trade Datas ... + * + * @param signal: XSignal instance Reference, Issued Signal ... + */ + void Add(XSignal &signal) + { + // + // Check Signal is Valid and also not Exists + // in Datas ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + if (hasItem) + { + return; + } + + // + // Initialize Data Item and Add it to Collection of Datas + // if Everythings OK ... + X121SMCTradeData data; + bool isInited = data.Init(signal); + if (isInited) + { + // + Add(data); + SaveSignal(data); + } + } + + /** + * Update a Registered Data Model by Providing Specified Signal ... + * usually used When a signal Modified after Executed for Conditionally Signals ... + * + * @param signal: XSignal instance Reference, Issued Signal ... + */ + void Update(XSignal &signal) + { + // + // Validate Signal ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal Registered Before ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + bool isUpdated = false; + if (!hasItem) + { + // + // Add New Item if not Exists ... + Add(signal); + isUpdated = true; + } + else + { + // + // Update Data Model in Datas Collection ... + isUpdated = mData[idx].Update(signal); + } + + // + if (isUpdated) + { + SaveSignal(mData[idx]); + } + } + + /** + * Update a Registered Data Model by Providing Specified Position ... + * used for Updating Positions Data or When a Conditional Order Executed as Position ... + * + * @param position: XPosition instance Referece ... + */ + void Update(XPosition &position) + { + // + // Validate Position ... + if (!position.IsValid()) + { + return; + } + + // + // Check Position Registered Before ... + int idx = -1; + bool hasItem = HasItem( + position, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Model in Datas Collection ... + mData[idx].Update(position); + } + + /** + * Remove Specified Registered Signal from Data Collection ... + * + * @param signal: XSignal instance Reference ... + */ + void Remove(XSignal &signal) + { + // + // Validate Signal ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal is Registered or not ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Remove Data From Collection ... + ArrayRemove( + mData, + idx, + 1 // + ); + } + + /** + * Handle Position Execution Finished by Providing a Deal ... + * usually used when a Position TP/SL Triggered ... + * + * @param deal: XDeal instance Reference ... + */ + void Finish(const XDeal &deal) + { + // + // Validate Deal ... + // Check Specified Data Registered or not ... + int idx = -1; + bool hasItem = HasItem( + deal.positionId, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Info ... + mData[idx].swap = deal.swap; + mData[idx].endTime = deal.time; + mData[idx].profit = deal.profit; + + // + // Check Deal Reason ... + bool isTP = deal.reason == DEAL_REASON_TP || + (deal.reason == DEAL_REASON_SL && deal.profit > 0); + bool isSL = deal.reason == DEAL_REASON_SL && deal.profit < 0; + + // + // Prepare Specified Message Based on Deal Reason ... + mData[idx].message = + isTP + ? "TP" + : isSL + ? "SL" + : ""; + + // + // Handle Symbol Positions TP or SL Actions ... + if (isTP || isSL) + { + // + // Check Symbol Position Info Model Exists ... + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].GetSymbol(), + symbolIDX // + ); + + // + // Try to Update or Add Symbol Position Info ... + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].GetSymbol(); + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + // Call Propper TP / SL Handlers on Symbol Position Info Model ... + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + // Add Model to Symbol Positions Collection ... + AddRef( + info, + mSymbolInfos // + ); + + // + // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... + HandlePauseSymbol(mData[idx].GetSymbol()); + } + + // + // Save Collector Calss Data Model ... + Save(idx); + } + + /** + * Handle Position Execution Finished by Providing some Data ... + * usually used when a Position Force Closed Triggered ... + * + * @param ticket: ULong, Position ticket ... + * @param position: XPosition instance Reference ... + * @param comment: String, Force Closing Comment ... + */ + void Finish( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + // Validate and Check Data Registered or not ... + int idx = -1; + bool hasItem = HasItem( + ticket, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Info ... + mData[idx].swap = position.swap; + mData[idx].endTime = TimeCurrent(); + mData[idx].profit = position.profit; + + // + mData[idx].message = comment; + + // + // Handle Force Closes as TP/SL for Updating + // Symbol Info Positions ... + bool handleForceClose = true; + if (handleForceClose) + { + // + // Simulate TP/SL based on Closing Profit ... + bool isTP = position.profit > 0; + bool isSL = position.profit <= 0; + + // + if (isTP || isSL) + { + // + // Check Symbol Position Info Model Exists ... + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].GetSymbol(), + symbolIDX // + ); + + // + // Try to Update or Add Symbol Position Info ... + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].GetSymbol(); + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + // Call Propper TP / SL Handlers on Symbol Position Info Model ... + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + // Add Model to Symbol Positions Collection ... + AddRef( + info, + mSymbolInfos // + ); + + // + // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... + HandlePauseSymbol(mData[idx].GetSymbol()); + } + + // + // Save Collector Calss Data Model ... + Save(idx); + } + } + + /** + * Update New Open Positions Data on Collection ... + */ + void HandleNewPosition() + { + // + // Retrieve Last Open Position ... + ulong lastOpenPositionTicket = mTrader.GetLastOpenPositionTicket(); + if (lastOpenPositionTicket == 0) + { + return; + } + + // + XPosition position; + bool hasPosition = mTrader.GetPosition( + lastOpenPositionTicket, + position // + ); + if (!hasPosition) + { + return; + } + + // + // Calculate Position Commission ... + double commission = mTrader.GetPositionCommission(position.ticket); + position.commission = commission; + + // + // Apply Updates on Data Collection ... + int idx = -1; + bool hasItem = HasItemByPosition( + position, + idx // + ); + if (!hasItem) + { + return; + } + + // + mData[idx].UpdatePosition(position); + } + + // + // Symbol Position Info Actions ... + + /** + * Retrieve Specified Symbols Info ... + * + * @param symbol: String ... + * @param info: X121SMCSymbolPositionInfo instance ... + * + * @return ( bool ) + */ + bool GetSymbolInfo( + string symbol, + X121SMCSymbolPositionInfo &info // + ) + { + // + bool result = false; + + // + info.Clean(); + + // + int symbolIDX = -1; + result = HasSymbol( + symbol, + symbolIDX // + ); + if (!result) + { + return result; + } + + // + info = mSymbolInfos[symbolIDX]; + + // + return result; + } + + /** + * Pause Specified Symbol Trading ... + * + * @param symbol: String ... + */ + void HandlePauseSymbol(string symbol) + { + // + if (!IsValid(symbol)) + { + return; + } + + // + int idx = -1; + bool hasItem = HasSymbol( + symbol, + idx // + ); + if (!hasItem) + { + return; + } + + // + int maxAllowedSLToPause = MaxAllowedSLToPauseSignallingPerSymbol(); + int pauseDelay = PauseSignallingAfterReachesMaxAllowedSLInSecconds(); + if (maxAllowedSLToPause <= 0 || pauseDelay <= 0) + { + return; + } + + // + bool canPauseSymbol = + mSymbolInfos[idx].IsEnable() && + mSymbolInfos[idx].countedSLs >= maxAllowedSLToPause; + if (!canPauseSymbol) + { + return; + } + + // + mSymbolInfos[idx].Pause(pauseDelay); + + // + string message = "Pause (" + symbol + ") until: (" + ToString(mSymbolInfos[idx].enableAt) + ") ..."; + Alert(message); + + // + } + + /** + * Reset Specified Symbol Info ... + * + * @param symbol: String ... + */ + void ResetSymbolInfo(string symbol) + { + // + if (!IsValid(symbol)) + { + return; + } + + // + int symbolIDX = -1; + bool hasSymbol = HasSymbol( + symbol, + symbolIDX // + ); + if (!hasSymbol) + { + return; + } + + // + mSymbolInfos[symbolIDX].Reset(); + + // + string message = "Reset " + symbol + ", Pause State ..."; + Alert(message); + } + + /** + * Reset All Paused Symbols ... + */ + void ResumePausedSymbols() + { + // + int count = ArraySize(mSymbolInfos); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mSymbolInfos[i].Reset(); + } + + // + string message = "Force Resume Paused Symbols ..."; + Alert(message); + } + + // + // Signal Execution Actions ... + + /** + * Validate Signal For Execution ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * + * @return ( bool ) + */ + bool CanExecute( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT &state // Execution State + ) + { + // + bool result = false; + + // + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + int symbolIDX = -1; + bool hasSymbolInfo = HasSymbol( + signal.symbol, + symbolIDX // + ); + + // + // Check rading Not Paused ... + result = + !hasSymbolInfo || + mSymbolInfos[symbolIDX].IsEnable(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + bool isLong = IsLong(signal.type); + + // + // Chekc Signalling Enable or not ... + result = + isLong + ? mAllowLong + : mAllowShort; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + // Check Signal is Support or not ... + bool isSupport = IsSupport(signal.comment); + result = !isSupport; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + ENUM_X_POSITION_TYPES pType = ToPositionType(signal.type); + double requiredProfitForAcceptNext = LastPositionProfitForAcceptNextInPoint(); + + // + // Implement Same Signal Conditions ... + XPosition smaeSymbolPositions[]; + int sameSymbolPositionsCount = mTrader.GetPositions( + smaeSymbolPositions, + signal.symbol, + signal.provider, + signal.period, + pType, + true, // Filter By Magic ... + true // Force Clean ... + ); + XPosition youngestSame; + int youngestSameAge = GetYoungest( + youngestSame, + smaeSymbolPositions // + ); + + // + double youngestSameProfitInPoint = youngestSame.GetProfitInPoint(); + + // + result = + sameSymbolPositionsCount == 0 || + (sameSymbolPositionsCount <= 0 + ? true + : requiredProfitForAcceptNext <= 0 + ? true + : youngestSameAge >= 0 && + youngestSameProfitInPoint >= requiredProfitForAcceptNext); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR; + return result; + } + + // + // Retrieve Longs and Shorts ... + XPosition longs[]; + XPosition shorts[]; + bool useMaxAllowedPositionsPerSymbol = UseMaxAllowedSignalsPerSymbol(); + + // + // Retrieve Positions ... + if (useMaxAllowedPositionsPerSymbol) + { + // + mTrader.GetPositions( + longs, + shorts, + signal.symbol, + signal.provider // + ); + } + else + { + // + mTrader.GetPositions( + longs, + shorts, + NULL, // All Symbols ... + signal.provider // + ); + } + + // + // Counting ... + int longsCount = ArraySize(longs); + int shortsCount = ArraySize(shorts); + + // + int maxAllowedLongs = MaxAllowedLongs(); + int maxAllowedShorts = MaxAllowedShorts(); + + // + // Check Max Allowed Positions ... + if (maxAllowedLongs > 0 || + maxAllowedShorts > 0) + { + // + if (isLong && maxAllowedLongs > 0 && longsCount > 0) + { + result = longsCount < maxAllowedLongs; + } + else if (!isLong && maxAllowedShorts > 0 && shortsCount > 0) + { + result = shortsCount < maxAllowedShorts; + } + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + } + + // + // Check Delays Bar if Provided ... + int delaysBarBetweenTwoSignal = DelaysBetweenTwoSignalsInBar(); + if (delaysBarBetweenTwoSignal > 0) + { + // + // Try To Detect Youngest Position ... + int youngestAge = 0; + XPosition youngestPosition; + + // + // Long Positions when there are Longs ... + if (isLong && longsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + longs // + ); + } + // + // Short Positions when there are Shorts ... + else if (!isLong && shortsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + shorts // + ); + } + + // + // Check Delays When Youngest Position Exists ... + if (youngestAge > 0 && youngestPosition.IsValid()) + { + // + result = youngestAge >= delaysBarBetweenTwoSignal; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; + return result; + } + } + + // + // Check Delays When Youngest Position is not Exists ... + if (!youngestPosition.IsValid()) + { + // + // Try to Detect Last Issued Signal in Model Collections ... + int symbolIDX = FindLastExecutedSignalItem(signal); + if (IsValidIndex(symbolIDX)) + { + // + // Calculate Requirements ... + datetime cTime = TimeCurrent(); + int signalPeriodSeconds = PeriodSeconds(signal.period); + datetime lastExecutedTime = mLastExecutedSignals[symbolIDX].time; + datetime passedTime = ((datetime)lastExecutedTime + + ((delaysBarBetweenTwoSignal * signalPeriodSeconds))); + + // + // Check Conditions ... + result = cTime >= passedTime; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; + return result; + } + } + } + } + + // + // Check Max Drawdown Percent for Open Trades ... + double maxAllowedDrawdownPercent = MaxAllowedDrawdownToOpenTrades(); + if (maxAllowedDrawdownPercent > 0) + { + // + // Calculate and Update Drawdown Percent ... + double cdPercent = CalculateMaxDrawdownPercent(); + + // + result = cdPercent < maxAllowedDrawdownPercent; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + } + + // + // Check Spread ... + double spread = GetSpread(signal.symbol); + double maxAllowedSpread = MaxAllowedSpread(); + if (maxAllowedSpread > 0) + { + // + result = spread <= maxAllowedSpread; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_SPREAD; + return result; + } + } + + // + return result; + } + + /** + * Execute Specific Signal using Trade Handler ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * @param ignorePolicies: Boolean ... + * + * @return ( bool ) + */ + bool ExecuteSignal( + XSignal &signal, // Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State + bool ignorePolicies = false // Ignore Execution Policies + ) + { + // + bool result = false; + + // + // Check Signal Validation ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Check Policies ... + if (!ignorePolicies) + { + // + // Filter Signals if Necessary ... + result = CanExecute( + signal, + state // + ); + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + + // + return result; + } + } + + // + // Apply Additional Volume to Signal if Provided ... + double additionalVolume = AdditionalVolume(); + if (additionalVolume > 0) + { + signal.volume += mAdditionalVolume; + } + + // + // Execute Signal ... + result = mTrader.ExecuteSignal( + signal, + state // + ); + if (result) + { + // + // Add XTradeHandler Data ... + Add(signal); + + // + // Handle Last Executed Signal ... + HandleSignalExecuted(signal); + + // + // Alert Executed Signal ... + string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " Executed Successfully ..."; + Alert(msg); + } + + // + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + } + + // + return result; + } + + /** + * Execute Specific Signal using Trade Handler ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * @param ignorePolicies: Boolean ... + * + * @return ( bool ) + */ + bool ExecuteSignal( + XSignal &signal, // Signal for Execution + X121SMCStrategyConditions &conditions, // Signal Conditions + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State + bool ignorePolicies = false // Ignore Execution Policies + ) + { + // + bool result = false; + + // + // Check Signal Validation ... + result = signal.IsValid() && + conditions.IsValid(); + if (!result) + { + return result; + } + + // + // Check Policies ... + if (!ignorePolicies) + { + // + // Filter Signals if Necessary ... + result = CanExecute( + signal, + state // + ); + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + + // + return result; + } + } + + // + // Apply Additional Volume to Signal if Provided ... + double additionalVolume = AdditionalVolume(); + if (additionalVolume > 0) + { + signal.volume += mAdditionalVolume; + } + + // + // Execute Signal ... + result = mTrader.ExecuteSignal( + signal, + state // + ); + if (result) + { + // + // Add XTradeHandler Data ... + Add(signal); + + // + // Handle Last Executed Signal ... + HandleSignalExecuted(signal); + + // + // Alert Executed Signal ... + string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " Executed Successfully ..."; + Alert(msg); + } + + // + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + } + + // + return result; + } + + /** + * Force Close Specified Positions ... + * + * @param symbol: String ... + * @param provider: String ... + * @param period: ENUM_TIMEFRAMES member ... + * @param type: ENUM_X_POSITION_TYPES member ... + * + * @return ( bool ) + */ + bool ForceClose( + string symbol = NULL, + string provider = NULL, + ENUM_TIMEFRAMES period = NULL, + ENUM_X_POSITION_TYPES type = NULL // + ) + { + // + bool result = false; + + // + XPosition positions[]; + int count = mTrader.GetPositions( + positions, + symbol, + provider, + period, + type // + ); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + datetime cTime = TimeCurrent(); + + // + string comment = "Force Close (" + ToString(count) + ") Positions At: " + ToFormatString(cTime) + "..."; + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + result = IsValidSize(closedPositionsCount); + if (result) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + string message = "Force Close (" + ToString(count) + ") Positions At: " + + ToFormatString(cTime) + " Successfully ..."; + Alert(message); + } + + // + return result; + } + + /** + * Force Close Positions ... + * + * @return ( bool ) + */ + bool ForceClose( + XPosition &positions[], + string comment, + string notificationMessage // + ) + { + // + bool result = false; + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + result = IsValidSize(closedPositionsCount); + if (result) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + if (IsValid(notificationMessage)) + { + Alert(notificationMessage); + } + } + + // + return result; + + // + return result; + } + + // + // Timing Actions ... + + /** + * Update Currently Open Positions Info on Data Collection ... + */ + void UpdateData() + { + // + // Retrieve Positions ... + XPosition positions[]; + int count = mTrader.GetPositions(positions); + if (!IsValidSize(count)) + { + return; + } + + // + // Loop Through Positions ... + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Position Registered as Data or not ... + int idx = -1; + bool isExists = HasItem( + iPosition.ticket, + idx // + ); + if (isExists) + { + // + // Update Position Data ... + mData[idx].Update(iPosition); + } + } + } + + /** + * Handle Positiona Protections + */ + void HandleProtection() + { + // + string prefix = "Protector: "; + + // + // Implement Protection Senario Here ... + int count = Count(); + if (!IsValidSize(count)) + { + // + currentDrawdown = 0; + return; + } + + // + // Calculate Max Same Time Trades ... + maxSameTimeTrades = + maxSameTimeTrades == 0 || + maxSameTimeTrades < count + ? count + : maxSameTimeTrades; + + // + double bepSummary = 0; + double volumeSummary = 0; + double profitSummary = 0; + XPosition positions[]; + bool isProtected = false; + + // + // Loop through Open Positions ... + for (int i = 0; i < count; i++) + { + // + X121SMCTradeData iData = mData[i]; + + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iData.ticket, + iPosition // + ); + if (!hasPosition) + { + continue; + } + AddRef( + iPosition, + positions // + ); + + // + // Calculate Break Even Point ... + double entry = iPosition.entry; + double points = iData.Points(); + double volume = iPosition.volume; + bool isLong = IsLong(iData.Type()); + double spread = GetSpread(iData.GetSymbol()); + double bep = iData.CalculateBreakEvenPoint(); + double exitPrice = GetExit( + iPosition.symbol, + iPosition.type // + ); + + // + double tps[]; + int reachedTPIndex = -1; + double reachedTPPrice = 0; + double reachedTPLevel = -1; + int tpLevelsCount = iPosition.CalculateTPLevels(tps); + iPosition.CalculateReahedTP( + reachedTPLevel, + reachedTPPrice // + ); + if (reachedTPLevel > 0) + { + // + reachedTPIndex = FindIndex( + reachedTPPrice, + tps // + ); + } + + // + bepSummary += bep; + volumeSummary += volume; + profitSummary += iPosition.profit; + + // + // All Protections Done for InProfit Positions ... + if (iData.profit > 0) + { + // + // Check Break Even ... + bool canRFOnBEP = iData.CanRiskFreeOnBreakEvenPoint(); + if (canRFOnBEP && reachedTPLevel > 0) + { + // + double tpLevel = iData.TPLevelForBreakEven(); + int tpIDX = (int)tpLevel - 1; + double rfTPPrice = tps[tpIDX]; + bool isSLReady = isLong + ? iPosition.sl < rfTPPrice + : iPosition.sl > rfTPPrice; + if (isSLReady && tpLevel == reachedTPLevel - 1) + { + // + double sl = rfTPPrice; + double tp = iPosition.tp; + string comment = "RF on BEP ..."; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + isProtected = true; + + // + string message = prefix + + ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " RF On BEP Successfully ..."; + Alert(message); + } + } + } + + // + // Check Partial Close ... + bool canPartialClose = iData.CanPartialClose(); + if (canPartialClose && reachedTPLevel > 0) + { + // + double mainVolume = iData.Volume(); + double currentVolume = iPosition.volume; + double partialCloseOnTP = iData.PartialCloseOnTPLevel(); + double partialCloseVolumeMultiplier = iData.PartialCloseMultiplier(); + double closeVolume = currentVolume * partialCloseVolumeMultiplier; + closeVolume = NormalizeVolume(closeVolume, iPosition.symbol); + canPartialClose = + currentVolume == mainVolume && + reachedTPLevel == partialCloseOnTP; + if (canPartialClose) + { + // + string comment = "PC On TP Level: " + ToString(partialCloseOnTP) + " ..."; + bool isModified = mTrader.ClosePartial( + iData.ticket, + closeVolume, + comment // + ); + if (isModified) + { + // + isProtected = true; + + // + string message = prefix + + ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " PC (" + ToString(closeVolume) + ") On TP Level: " + + ToString(partialCloseOnTP) + " Successfully ..."; + Alert(message); + + // + // Finish Position ... + if (closeVolume == mainVolume) + { + // + Finish( + iPosition.ticket, + iPosition, + comment // + ); + + // + break; + } + } + } + } + + // + // Check for SL Trail ... + bool canTrailSL = iData.CanTrailSL(); + if (canTrailSL && reachedTPLevel > 0) + { + // + double tSLTPPrice = 0; + + // + double startTrailTPLevel = iData.TrailSLStartOnReachTPLevel(); + if (iData.lastTrailedTPLevel > 0) + { + startTrailTPLevel = iData.lastTrailedTPLevel + 1; + } + + // + canTrailSL = IsValidIndex(reachedTPIndex) && + reachedTPLevel >= startTrailTPLevel; + if (canTrailSL) + { + // + tSLTPPrice = + reachedTPIndex == 0 + ? tps[reachedTPIndex] + : tps[reachedTPIndex - 1]; + + // + canTrailSL = + tSLTPPrice > 0 && + iPosition.sl == 0 + ? (isLong + ? tSLTPPrice > iPosition.entry && + tSLTPPrice < iPosition.price + : tSLTPPrice < iPosition.entry && + tSLTPPrice > iPosition.price) + : (isLong + ? tSLTPPrice > iPosition.sl && + tSLTPPrice > iPosition.entry && + tSLTPPrice < iPosition.price + : tSLTPPrice < iPosition.sl && + tSLTPPrice < iPosition.entry && + tSLTPPrice > iPosition.price); + } + + // + if (canTrailSL) + { + // + string comment = "Trail SL on Reached TP: " + ToString(reachedTPLevel) + " ..."; + double sl = tSLTPPrice; + double tp = iPosition.tp; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + isProtected = true; + + // + // Update Last Trailed TP Level ... + mData[i].lastTrailedTPLevel = reachedTPLevel; + + // + string message = prefix + + ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " Trailed SL On Reached TP: " + ToString(reachedTPLevel) + + " Successfully ..."; + Alert(message); + } + } + } + + // + // Handle RF On Target ... + double targets[]; + int targetsCount = iData.Targets(targets); + bool hasTargets = IsValidSize(targetsCount); + if (hasTargets) + { + // + for (int k = 0; k < targetsCount; k++) + { + // + double target = targets[k]; + bool isValidTarget = + iData.lastTarget == 0 + ? true + : isLong + ? target > iData.lastTarget + : target < iData.lastTarget; + if (!isValidTarget) + { + continue; + } + + // + double targetDelta = isLong + ? target + (15 * points) + : target - (15 * points); + bool canRF = + target > 0 && + (isLong ? target > entry + : target < entry) && + (isLong + ? iPosition.sl < target + : iPosition.sl > target) && + (isLong + ? iPosition.price > targetDelta + : iPosition.price < targetDelta); + if (canRF) + { + // + double sl = target; + double tp = iPosition.tp; + string comment = "RF On Target ..."; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + isProtected = true; + + // + // Update mData ... + mData[i].lastTarget = target; + + // + string message = prefix + + ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " RF On Traget: " + ToString(target) + + " Successfully ..."; + Alert(message); + } + } + } + } + } + } + + // + // Calculate Max Draw Down ... + maxDrawdown = + profitSummary < 0 && + (maxDrawdown == 0 || + maxDrawdown < profitSummary) + ? profitSummary + : maxDrawdown; + + // + // Calculate Current Drawdown ... + currentDrawdown = + profitSummary < 0 + ? profitSummary + : 0; + + // + // Checking Hedge ... + bool allowHedge = AllowHedging() && + !isProtected; + if (allowHedge) + { + // + double minHedgeVolumeStep = HedgingMinVolumeStep(); + int minRequiredPositionsForHedge = MinOpenTradesFroHedging(); + double minRequiredProfitPerVolumeStepForHedge = HedgeingMinRequiredProfitPerVolumeStep(); + + // + double minRequiredAdditionalProfit = + bepSummary + + ((volumeSummary / minHedgeVolumeStep) * minRequiredProfitPerVolumeStepForHedge); + + // + bool canHedge = AllowHedging() && + profitSummary > 0 && + minHedgeVolumeStep > 0 && + minRequiredProfitPerVolumeStepForHedge > 0 && + profitSummary >= minRequiredAdditionalProfit && + (minRequiredPositionsForHedge <= 0 + ? true + : count >= minRequiredPositionsForHedge); + if (canHedge) + { + // + string comment = "Hedge (" + ToString(ArraySize(positions)) + ") Positions By: " + ToString(profitSummary) + "..."; + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + if (IsValidSize(closedPositionsCount)) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + string message = "Hedge (" + ToString(ArraySize(positions)) + ") Positions By: " + + ToString(profitSummary) + " Successfully ..."; + Alert(message); + } + } + } + } + + // + // Protected ... + protected: + // + XCTrade *mTrader; // Instance of Trader Class + X121SMCTradeCollector *mCollector; // Instance of Trade Collector Class + + // + X121SMCTradeData mData[]; // Hold Trade Data + X121SMCSymbolPositionInfo mSymbolInfos[]; // Symbol Positions Info + XSymbolLastPosition mLastExecutedSignals[]; // Last Executed Signals + + // + void AlertSignalExecutionFailed( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT state // + ) + { + // + // Alert Signal Execution Failed ... + string msg = "Failed To Execute " + + (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " due Reason: " + ToString(state) + " ..."; + Alert(msg); + } + + // + // Private ... + private: + // + // Props ... + + // + // Read Only ... + int maxSameTimeTrades; // Holds Max Same Time Trades + double maxDrawdown; // Max Drawdown + double currentDrawdown; // Current Drawdown + double drawdownPercent; // Drawdown Percent + double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation + + // + bool mSaveSignals; // Save Signals + bool mSaveTrades; // Save Trades + bool mSaveConditions; // Save SL Conditions + + // + // Signalling Props ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + int mMaxAllowedLongs; // Max Allowed Long Signals ... + int mMaxAllowedShorts; // Max Allowed Short Signals ... + bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ... + double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ... + int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ... + double mMaxAllowedSpread; // Max Allowed Spread for Signalling ... + double mAdditionalVolume; // Volume Additional ... + + // + // Risk Management Props ... + double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ... + int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ... + int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + + // + // Protection Props ... + bool mAllowHedging; // Allow Hedge Positions ... + int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ... + double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ... + double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ... + + // + // Common Functions ... + + // + // Count Data ... + int Count() + { + return ArraySize(mData); + } + + // + // Add Item ... + bool Add(X121SMCTradeData &item) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + int index = -1; + if (item.ticket > 0) + { + // + result = !HasItem( + item.ticket, + index // + ); + } + else + { + // + result = !HasItem( + item.signal, + index // + ); + } + if (!result || IsValidIndex(index)) + { + // + result = false; + return result; + } + + // + AddRef( + item, + mData // + ); + + // + return result; + } + + // + // Find Item Index ... + bool HasItem( + ulong ticket, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + result = mData[i].IsOwn(ticket); + if (result) + { + // + index = i; + break; + } + } + + // + return result; + } + + // + bool HasItem( + XSignal &signal, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = signal.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwn(signal); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool HasItem( + XPosition &position, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = position.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwn(position); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool HasItemByPosition( + XPosition &position, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = position.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwnPosition(position); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Find Specific Symbo Indo Item index ... + * + * @param symbol: String ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool HasSymbol( + string symbol, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = IsValid(symbol); + if (!result) + { + return result; + } + + // + int count = ArraySize(mSymbolInfos); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mSymbolInfos[i] + .IsOwn(symbol); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + void Save(int index) + { + // + int count = Count(); + if (!IsValidIndex(index) || index > count - 1) + { + return; + } + + // + // Save Trade ... + if (mSaveTrades) + { + mCollector.Save(mData[index]); + } + + // + if (mSaveConditions) + { + mCollector.SaveConditions(mData[index]); + } + + // + // Remove Item From List ... + ArrayRemove( + mData, + index, + 1 // + ); + } + + // + void SaveSignal(X121SMCTradeData &item) + { + // + if (!mSaveSignals) + { + return; + } + + // + // Save Signal ... + mCollector.SaveSignal(item); + } + + // + // Find Last Signal Execution ... + int FindLastExecutedSignalItem(XSignal &signal) + { + // + int result = -1; + + // + if (!signal.IsValid()) + { + return result; + } + + // + int count = ArraySize(mLastExecutedSignals); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XSymbolLastPosition iLast = mLastExecutedSignals[i]; + if (iLast.symbol == signal.symbol && + iLast.provider == signal.provider) + { + // + result = i; + break; + } + } + + // + return result; + } + + // + // Handle Last Signal Execution ... + void HandleSignalExecuted(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + datetime cTime = TimeCurrent(); + int symbolIDX = FindLastExecutedSignalItem(signal); + bool hasItem = IsValidIndex(symbolIDX); + if (hasItem) + { + mLastExecutedSignals[symbolIDX].time = cTime; + } + else + { + // + XSymbolLastPosition item; + + // + item.time = cTime; + item.symbol = signal.symbol; + item.provider = signal.provider; + + // + AddRef( + item, + mLastExecutedSignals // + ); + } + } + + // + double CalculateMaxDrawdownPercent() + { + // + double result = 0; + + // + double mEquity = mTrader.mAccount.GetEquity(); + if (mEquity > currentDrawdown) + { + currentDrawdown = mEquity; + } + + // + if (currentDrawdown >= 0) + { + // + drawdownPercent = 0; + return result; + } + + // + drawdownPercent = (currentDrawdown - mEquity) / + (staticBalanceForCalculateDrawdown > 0 + ? staticBalanceForCalculateDrawdown + : currentDrawdown) * + 100; + drawdownPercent = NormalizeDouble(drawdownPercent, 3); + result = drawdownPercent; + + // + return result; + } + + // + void ResetProtections() + { + // + ResumePausedSymbols(); + Clean(mLastExecutedSignals); + } + + // + // End of XC121SMCTradeHandler Class ... +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Experts/x-121.smc.expert.class.mq5 b/BKPS/14031218/X121SMCEA/Experts/x-121.smc.expert.class.mq5 new file mode 100644 index 0000000..c79eaa1 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Experts/x-121.smc.expert.class.mq5 @@ -0,0 +1,2479 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121SMCExpert +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-expert.class.mq5" +#include "../../Helpers/x-saherelm.x121.xcc.helper.mq5" +#include "../../Helpers/x-saherelm.x121.xct.helper.mq5" +#include "../Classes/x-121.smc.x-tradehandler.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "../Strategy/x-121.smc.strategy.class.mq5" + +// +// Definitions ... +string XC121SMCExpertToken = "XC121SMCEA"; + +// +// Implementation ... + +class XC121SMCExpert : public XCBaseExpert +{ + // + public: + // + XCX121XCCHelper *xccHelper; + XCX121XCTHelper *xctHelper; + + // + // Signal Event Listener ... + TOnStopLoss OnPositionSLEventListener; + TOnTakeProfit OnPositionTPEventListener; + TOnPartialClose OnPositionPartialCloseEventListener; + TOnModify OnPositionModifiedEventListener; + TOnForceClose OnPositionForceCloseEventListener; + + // + TOnDealsChanged OnDealsChangedEventListener; + TOnOrdersChanged OnOrdersChangedEventListener; + TOnPositionsChanged OnPositionsChangedEventListener; + + // + TOnX121SMCSignal OnSignalEventListener; + + // + // Constructor(s) ... + XC121SMCExpert() + { + mShowCandles = false; + } + + // + // Deconstructor(s) ... + ~XC121SMCExpert() + { + Clean(mStrategies); + } + + // + // Getter(s) / Setter(s) ... + + // + // Signalling Props ... + + /** + * Get Allow Long Signals State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + // + mAllowLong = value; + ReConfigure(); + } + + /** + * Get Allow Short Signals State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signals State ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + // + mAllowShort = value; + ReConfigure(); + } + + /** + * Get Max Allowed Long Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedLongs() + { + return mMaxAllowedLongs; + } + + /** + * Set Max Allowed Long Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedLongs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedLongs = value; + ReConfigure(); + } + + /** + * Get Max Allowed Short Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedShorts() + { + return mMaxAllowedShorts; + } + + /** + * Set Max Allowed Short Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedShorts(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedShorts = value; + ReConfigure(); + } + + /** + * Get Use Max Allowed Signal Types Per Symbol State ... + * + * @return ( bool ) + */ + bool UseMaxAllowedSignalsPerSymbol() + { + return mUseMaxAllowedSignalsPerSymbol; + } + + /** + * Set Use Max Allowed Signal Types Per Symbol State ... + * + * @param value: Boolean ... + */ + void UseMaxAllowedSignalsPerSymbol(bool value) + { + // + mUseMaxAllowedSignalsPerSymbol = false; + ReConfigure(); + } + + /** + * Get Last Position Profit In Points for Accept new Signal ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double LastPositionProfitForAcceptNextInPoint() + { + return mLastPositionProfitForAcceptNextInPoint; + } + + /** + * Set Last Position Profit In Points for Accept new Signal ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void LastPositionProfitForAcceptNextInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mLastPositionProfitForAcceptNextInPoint = value; + ReConfigure(); + } + + /** + * Get Delay between two Signals in Bars ... + * 0 => Accept All ... + * + * @return ( int ) + */ + int DelaysBetweenTwoSignalsInBar() + { + return mDelaysBetweenTwoSignalsInBar; + } + + /** + * Set Delay between two Signals in Bars ... + * + * @param value: Integer ... + * 0 => Accept All ... + */ + void DelaysBetweenTwoSignalsInBar(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelaysBetweenTwoSignalsInBar = value; + ReConfigure(); + } + + /** + * Get Max Allowed Spread for Signalling ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread for Signalling ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void MaxAllowedSpread(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSpread = value; + ReConfigure(); + } + + /** + * Get Minimum Spread Verification for Signalling ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinRequiredVerificationForSpreadPass() + { + return mMinRequiredVerificationForSpreadPass; + } + + /** + * Set Minimum Spread Verification for Signalling ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinRequiredVerificationForSpreadPass(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinRequiredVerificationForSpreadPass = value; + ReConfigure(); + } + + // + // Trade ... + + /** + * Get Allow Open Trade On Signals State ... + * + * @return ( bool ) + */ + bool AllowTrade() + { + return mAllowTrade; + } + + /** + * Set Allow Open Trade On Signals State ... + * + * @param value: Boolean ... + */ + void AllowTrade(bool value) + { + mAllowTrade = value; + } + + /** + * Get Enable Trade on Signals on Time ... + * + * @return ( string ) + */ + string StartTradeAt() + { + return mStartTradeAt; + } + + /** + * Set Enable Trade on Signals on Time ... + * + * @param value: String ... + */ + void StartTradeAt(string value) + { + mStartTradeAt = value; + } + + /** + * Get Enable Trade on Signals on Time ... + * + * @return ( string ) + */ + string StopTradeAt() + { + return mStopTradeAt; + } + + /** + * Set Enable Trade on Signals on Time ... + * + * @param value: String ... + */ + void StopTradeAt(string value) + { + mStopTradeAt = value; + } + + /** + * Get Enable Close All Trades on Signals on Time ... + * + * @return ( string ) + */ + string CloseAllTradesAt() + { + return mCloseAllTradesAt; + } + + /** + * Set Enable Close All Trades on Signals on Time ... + * + * @param value: String ... + */ + void CloseAllTradesAt(string value) + { + mCloseAllTradesAt = value; + } + + // + // Risk Management Props ... + + /** + * Get Risk to Reward Ratio ... + * + * @return ( double ) + */ + double R2R() + { + return mR2R; + } + + /** + * Set Risk to Reward Ratio ... + * + * @param value: Double ... + */ + void R2R(double value) + { + // + if (value < 1) + { + value = 1; + } + + // + mR2R = value; + ReConfigure(); + } + + /** + * Get Static Volume ... + * + * @return ( double ) + */ + double Volume() + { + return mVolume; + } + + /** + * Set Static Volume ... + * + * @param value: Double ... + */ + void Volume(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mVolume = value; + ReConfigure(); + } + + /** + * Get Static Balance for Calculate Trade Volume ... + * + * @return ( double ) + */ + double StaticBalance() + { + return mStaticBalance; + } + + /** + * Set Static Balance for Calculate Trade Volume ... + * + * @param value: Argument 1 + */ + void StaticBalance(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mStaticBalance = value; + } + + /** + * Get Balance Used In Each Trade ... + * + * @return ( double ) + */ + double BalancePerTrade() + { + return mBalancePerTrade; + } + + /** + * Set Balance Used In Each Trade ... + * + * @param value: Argument 1 + */ + void BalancePerTrade(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mBalancePerTrade = value; + } + + /** + * Get Risk Percent Per Balance in Each Trade ... + * + * @return ( double ) + */ + double RiskPercentPerBalance() + { + return mRiskPercentPerBalance; + } + + /** + * Set Risk Percent Per Balance in Each Trade ... + * + * @param value: Double + */ + void RiskPercentPerBalance(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRiskPercentPerBalance = value; + ReConfigure(); + } + + /** + * Get Dynamic Risk Management State ... + * + * @return ( bool ) + */ + bool DynamicRiskManagement() + { + return mDynamicRiskManagement; + } + + /** + * Set Dynamic Risk Management State ... + * + * @param value: Boolean ... + */ + void DynamicRiskManagement(bool value) + { + // + mDynamicRiskManagement = value; + ReConfigure(); + } + + /** + * Get Use Dynamic Volume State ... + * + * @return ( bool ) + */ + bool UseDynamicVolume() + { + return mUseDynamicVolume; + } + + /** + * Set Use Dynamic Volume State ... + * + * @param value: Boolean ... + */ + void UseDynamicVolume(bool value) + { + // + mUseDynamicVolume = value; + ReConfigure(); + } + + /** + * Get Increase Volume Step ... + * + * @return ( double ) + */ + double DynamicVolumeStep() + { + return mDynamicVolumeStep; + } + + /** + * Set Increase Volume Step ... + * + * @param value: Double ... + */ + void DynamicVolumeStep(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mDynamicVolumeStep = value; + ReConfigure(); + } + + /** + * Get Balance Factor for Generate Dynamic Volume ... + * + * @return ( double ) + */ + double DynamicVolumeBalanceFactor() + { + return mDynamicVolumeBalanceFactor; + } + + /** + * Set Balance Factor for Generate Dynamic Volume ... + * + * @param value: Double ... + */ + void DynamicVolumeBalanceFactor(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDynamicVolumeBalanceFactor = value; + ReConfigure(); + } + + /** + * Get Max Allowed Drawdown Percent for Open Trades ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + * + * @return ( double ) + */ + double MaxAllowedDrawdownToOpenTrades() + { + return mMaxAllowedDrawdownToOpenTrades; + } + + /** + * Set Max Allowed Drawdown Percent for Open Trades ... + * + * @param value: Double ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + */ + void MaxAllowedDrawdownToOpenTrades(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 50) + { + value = 50; + } + + // + mMaxAllowedDrawdownToOpenTrades = value; + ReConfigure(); + } + + /** + * Get Max Allowed SL for Pause Signalling Per Symbol ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedSLToPauseSignallingPerSymbol() + { + return mMaxAllowedSLToPauseSignallingPerSymbol; + } + + /** + * Set Max Allowed SL for Pause Signalling Per Symbol ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedSLToPauseSignallingPerSymbol(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLToPauseSignallingPerSymbol = value; + ReConfigure(); + } + + /** + * Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int PauseSignallingAfterReachesMaxAllowedSLInSecconds() + { + return mPauseSignallingAfterReachesMaxAllowedSLInSecconds; + } + + /** + * Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value; + ReConfigure(); + } + + // + // Protection Props ... + + /** + * Get Allow Hedge Positions State ... + * + * @return ( bool ) + */ + bool AllowHedging() + { + return mAllowHedging; + } + + /** + * Set Allow Hedge Positions State ... + * + * @param value: Boolean ... + */ + void AllowHedging(bool value) + { + // + mAllowHedging = value; + ReConfigure(); + } + + /** + * Get Minimum Open Positions for Hedging ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinOpenTradesFroHedging() + { + return mMinOpenTradesFroHedging; + } + + /** + * Set Minimum Open Positions for Hedging ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinOpenTradesFroHedging(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinOpenTradesFroHedging = value; + ReConfigure(); + } + + /** + * Get Minimum Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgingMinVolumeStep() + { + return mHedgingMinVolumeStep; + } + + /** + * Set Minimum Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgingMinVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + if (value > 0 && value > 0.1) + { + value = 0.1; + } + + // + mHedgingMinVolumeStep = value; + ReConfigure(); + } + + /** + * Get Minimum Required Profit Per Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgeingMinRequiredProfitPerVolumeStep() + { + return mHedgeingMinRequiredProfitPerVolumeStep; + } + + /** + * Set Minimum Required Profit Per Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgeingMinRequiredProfitPerVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mHedgeingMinRequiredProfitPerVolumeStep = value; + ReConfigure(); + } + + // + // Actions ... + + /** + * Handle OnSignalRecieved Event ... + * + * @param signal: XSignal instance ... + * @param conditions: X121SMCStrategyConditions instance ... + */ + void HandleOnSignalRecieved( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + // Check Signal and Conditions Validations ... + + // + if (!signal.IsValid()) + { + return; + } + + // + if (!conditions.IsValid()) + { + return; + } + + // + bool isLong = IsLong(signal.type); + + // + // Notify When a Raw (Unfiltered) Signal Recieved + // if it's Provided ... + bool mAlertRawSignals = false; + if (mAlertRawSignals) + { + // + string msg = "Raw " + (IsLong(signal.type) ? "Long" : "Short") + + " Signal Recieved: (" + signal.provider + "," + + signal.symbol + "," + + ToString(signal.period) + + ") ..."; + + // + Alert(msg); + } + + // + // Apply Volume On Signal ... + ApplyVolumeOnSignal(signal); + + // + // Chekc Signalling Enable or not ... + bool canContinue = + isLong + ? AllowLong() + : AllowShort(); + if (!canContinue) + { + return; + } + + // + // TODO: Apply Filtering On Signal ... + bool isFiltered = false; + if (isFiltered) + { + // + mTradeHandler.Remove(signal); + return; + } + + // + // Attach Conditions Summary to Signal ... + string conditionsSummary = conditions.GenerateSummary( + false, + false, + true, + false // + ); + + // + // TODO: Retrieve Conditions Summary based on Filter ... + signal.conditions = conditionsSummary; + + // + datetime currentTime = TimeCurrent(); + + // + // Chack Allow Trades ... + bool allowTrade = AllowTrade(); + if (allowTrade) + { + // + string startTime = StartTradeAt(); + string endTime = StopTradeAt(); + bool isTimePassed = IsTimeInRange( + TimeCurrent(), + startTime, + endTime // + ); + + // + if (isTimePassed) + { + // + // Execute Signal Using Trade Handler ... + ENUM_X_SIGNAL_EXECUTION_RESULT state; + bool isExecuted = mTradeHandler.ExecuteSignal( + signal, + conditions, + state, + false // ignore Policies ... + ); + } + else + { + // + string msg = "Failed To Execute " + + (IsLong(signal.type) + ? "Long" + : "Short") + + " Signal Recieved: (" + + signal.provider + "," + + signal.symbol + "," + + ToString(signal.period) + + ") due Trading offTime ..."; + + // + Alert(msg); + } + } + else + { + // + // Only Alert Signals ... + string msg = (IsLong(signal.type) + ? "Long" + : "Short") + + " Signal Recieved: (" + + signal.provider + "," + + signal.symbol + "," + + ToString(signal.period) + + ") ..."; + + // + Alert(msg); + } + + // + signal.Clean(); + conditions.Clean(); + } + + // + // Override Actions ... + + /** + * Apply Default Configurations ... + */ + void DefaultConfigure() override + { + // + // Commons ... + Slippage(10); + TagPrefix(""); + MagicNumber(1694056); + + // + // Symbol ... + SetSymbol(_Symbol); + SetPeriod(_Period); + MultiSymbol(false); + Symbols("EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb"); + + // + // Signalling ... + Disabled(false); + AllowLong(true); + AllowShort(true); + + // + string tag = GetTag(); + + // + // Alert ... + SetAlertPrefix(tag); + SetAlertLogAlerts(true); + SetAlertPushAlerts(true); + SetAlertMailAlerts(false); + SetAlertEnableAlerts(true); + SetAlertTerminalAlerts(false); + + // + // Reports ... + ReportNewDays(true); + ReportNewWeeks(false); + ReportNewHours(false); + ReportNewMonths(false); + + // + R2R(1); + + // + // Volume Default Configurations ... + Volume(0.01); + UseDynamicVolume(false); + DynamicVolumeStep(0.01); + DynamicVolumeBalanceFactor(200); + + // + RiskPercentPerBalance(0); + DynamicRiskManagement(false); + } + + /** + * Vaslidate Inputs ... + * + * @return ( bool ) + */ + bool ValidateInputs() override + { + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + Slippage() > 0 && + MagicNumber() > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + // Checking Volume ... + bool isVolumeValid = true; + if (UseDynamicVolume()) + { + // + isVolumeValid = + DynamicVolumeStep() > 0 && + DynamicVolumeBalanceFactor() > 0; + if (!isVolumeValid) + { + errMessage += "Dynamic Volume configurations error;" + "\n"; + } + } + isVolumeValid = isVolumeValid && + Volume() > 0; + if (!isVolumeValid) + { + errMessage += "Static Volume configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Volume Coniguration ... + isVolumeValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + errMessage = " Errors: \n" + errMessage; + Alert(errMessage); + } + + // + return result; + } + + // + // Initializers and DeInitializers ... + + /** + * Initial EA Requirements ... + * + * @return ( bool ) + */ + bool InitEA() override + { + // + bool result = true; + + // + // Initialize Indicator Helpers ... + + // + X121XCCInputs xccInputs; + xccInputs.Default(); + xccInputs.showCandles = mShowCandles; + xccHelper = new XCX121XCCHelper(); + result = xccHelper.Init( + _Symbol, + _Period, + xccInputs // + ); + if (!result) + { + return result; + } + + // + X121XCTInputs xctInputs; + xctInputs.Default(); + xctHelper = new XCX121XCTHelper(); + result = xctHelper.Init( + _Symbol, + _Period, + xctInputs // + ); + if (!result) + { + return result; + } + + // + // Configure Alerts ... + SetAlertPrefix(GetTag()); + SetAlertEnableAlerts(GetAlertEnableAlerts()); + SetAlertLogAlerts(GetAlertLogAlerts()); + SetAlertMailAlerts(GetAlertMailAlerts()); + SetAlertPushAlerts(GetAlertPushAlerts()); + SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + // Create Trader Instance and Configure it ... + mTrader = new XCTrade( + Slippage(), + MagicNumber() // + ); + mTrader.AddOnStopLossEventHandler(OnPositionSLEventListener); + mTrader.AddOnTakeProfitEventHandler(OnPositionTPEventListener); + mTrader.AddOnDealsChangedEventHandler(OnDealsChangedEventListener); + mTrader.AddOnOrdersChangedEventHandler(OnOrdersChangedEventListener); + mTrader.AddOnModifyPositionEventHandler(OnPositionModifiedEventListener); + mTrader.AddOnPositionsChangedEventHandler(OnPositionsChangedEventListener); + mTrader.AddOnForceClosePositionEventHandler(OnPositionForceCloseEventListener); + mTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialCloseEventListener); + + // + // Initialize Trade Handler ... + mTradeHandler = new XC121SMCTradeHandler(mTrader); + mTradeHandler.SaveTrades(false); + mTradeHandler.SaveSignals(false); + mTradeHandler.SaveConditions(false); + + // + ReConfigureTradeHandler(); + + // + // Parsers ... + XSymbolParser _symbolParser; + + // + // Single Symbol ... + if (!MultiSymbol()) + { + // + // Register Strategy ... + + // + // Create Class Instance ... + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCStrategy( + _Symbol, + _Period // + ); + + // + iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener); + + // + ConfigureStrategy(iX121SMCStrategy); + RegisterStrategy(iX121SMCStrategy); + } + // + // Multi Symbol ... + else + { + // + // Parse Symbols ... + string symbols[]; + int symbolsCount = SplitContent( + symbols, + Symbols() // + ); + result = IsValidSize(symbolsCount); + if (!result) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + // Select Symbol ... + string iSymbol = symbols[i]; + + // + // Register Strategy Based On Symbol ... + + // + // Parse Symbol ... + bool isEURUSD = _symbolParser.IsEURUSD(_Symbol); + bool isGBPUSD = _symbolParser.IsGBPUSD(_Symbol); + bool isEURGBP = _symbolParser.IsEURGBP(_Symbol); + bool isUSDCHF = _symbolParser.IsUSDCHF(_Symbol); + bool isEURCHF = _symbolParser.IsEURCHF(_Symbol); + bool isUSDJPY = _symbolParser.IsUSDJPY(_Symbol); + bool isEURJPY = _symbolParser.IsEURJPY(_Symbol); + bool isUSDCAD = _symbolParser.IsUSDCAD(_Symbol); + bool isEURCAD = _symbolParser.IsEURCAD(_Symbol); + bool isAUDUSD = _symbolParser.IsAUDUSD(_Symbol); + bool isEURAUD = _symbolParser.IsEURAUD(_Symbol); + bool isNZDUSD = _symbolParser.IsNZDUSD(_Symbol); + bool isEURNZD = _symbolParser.IsEURNZD(_Symbol); + + // + // Check Symbol Can Register or not ... + bool canRegisterStrategy = true; + + // + if (canRegisterStrategy) + { + // + // Create Class Instance ... + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCStrategy( + iSymbol, + _Period // + ); + + // + iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener); + + // + // Register Strategy ... + ConfigureStrategy(iX121SMCStrategy); + RegisterStrategy(iX121SMCStrategy); + } + } + + // + Clean(symbols); + } + + // + return result; + } + + /** + * Destroy all Initialized EA Requirements ... + */ + void DestroyEA() override + { + // + ZeroMemory(xccHelper); + ZeroMemory(xctHelper); + ZeroMemory(mTradeHandler); + + // + delete xccHelper; + delete xctHelper; + delete mTradeHandler; + + // + Clean(mStrategies); + } + + /** + * Call all Registered Strategies On Tick ... + */ + void HandleStrategiesOnTick() override + { + // + // Check Force Close ... + string forceCloseTimeStr = CloseAllTradesAt(); + if (IsValid(forceCloseTimeStr)) + { + // + datetime forceCloseTime = ParseDateTimeFromTimeString(forceCloseTimeStr); + bool canForceClose = IsTimeInRange( + TimeCurrent(), + forceCloseTime // + ) && + !mIsForceCloseAtTime; + if (canForceClose) + { + mIsForceCloseAtTime = mTradeHandler.ForceClose(); + } + } + + // + // Update Positions Data ... + mTradeHandler.UpdateData(); + + // + // Protect Positions ... + mTradeHandler.HandleProtection(); + + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + // Call Tick Handler Function ... + mStrategies[i].HandleTick(); + } + } + + /** + * Handle Strategies Guards ... + */ + void HandleStrategiesGuard() override + { + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions( + positions, // Result ... + NULL, // Symbol ... + NULL, // Provider ... + NULL, // Period ... + X_POSITION_TYPE_ALL // All Types ... + ); + if (!IsValidSize(positionsCount)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + // Call Tick Handler Function ... + X121SMCGuard iGuards[]; + bool hasGuards = mStrategies[i].HandleGuard( + iGuards, + positions // + ); + if (hasGuards) + { + HandleGuards(iGuards); + } + } + + // + Clean(positions); + } + + // + // Event Handlers ... + + /** + * Calls When a Deals Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnDealsChanged(int count) override + { + } + + /** + * Calls When a Order Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnOrdersChanged(int count) override + { + } + + /** + * Calls When a Positions Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnPositionsChanged(int count) override + { + // + if (IsValidSize(count)) + { + mTradeHandler.HandleNewPosition(); + } + } + + /** + * Calls When a Position's SL Triggered ... + * + * @param deal: XDeal instance ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) override + { + // + // Finish ... + mTradeHandler.Finish(deal); + + // + HandleReportBalance(); + } + + /** + * Calls When a Position's TP Triggered ... + * + * @param deal: XDeal instance ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) override + { + // + // Finish ... + mTradeHandler.Finish(deal); + + // + bool useDynamicRiskManagement = DynamicRiskManagement(); + if (useDynamicRiskManagement) + { + mTradeHandler.ResetSymbolInfo(deal.symbol); + } + + // + HandleReportBalance(); + } + + /** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) override + { + // + // Finish ... + mTradeHandler.Finish( + ticket, + position, + comment // + ); + + // + HandleReportBalance(); + } + + /** + * Reset All Paused Symbols on Each New Days ... + */ + void HandleOnNewDay() override + { + // + mIsForceCloseAtTime = false; + mTradeHandler.ResumePausedSymbols(); + } + + /** + * Re Configure Materials on Properties Changed ... + */ + void ReConfigure() override + { + // + ReConfigureTradeHandler(); + ReConfigureAllStrategies(); + } + + /** + * Generate Identifier Tag ... + * + * @return ( string ) + */ + string GetTag() override + { + // + string result = NULL; + + // + string tagPrefix = TagPrefix(); + if (IsValid(tagPrefix)) + { + result = tagPrefix; + } + else + { + result = ""; + } + + // + result = + XC121SMCExpertToken + result; + + // + return result; + } + + // + protected: + // + + // + // Props ... + + // + XC121SMCTradeHandler *mTradeHandler; // Trade Handler ... + XCX121SMCBaseStrategy *mStrategies[]; // Registere Strategies in EA ... + + // + // Actions ... + + /** + * Apply Volume Based On Configurations on Signal ... + * + * @param signal: XSignal instance + */ + void ApplyVolumeOnSignal(XSignal &signal) + { + // + if (signal.ignoreEAVolume) + { + return; + } + + // + double staticVolume = Volume(); + double fVolume = staticVolume > 0 + ? staticVolume + : 0.01; + + // + double staticBalance = StaticBalance(); + double accountBalance = mTrader.mAccount.GetBalance(); + double balance = staticBalance > 0 + ? staticBalance + : accountBalance; + + // + bool useDynamicVolume = UseDynamicVolume(); + double balancePerTrade = BalancePerTrade(); + double dynamicVolumeStep = DynamicVolumeStep(); + double riskPercentPerBalance = RiskPercentPerBalance(); + bool allowDynamicRiskManagement = DynamicRiskManagement(); + double dynamicVolumeBalanceFactor = DynamicVolumeBalanceFactor(); + + // + // Apply Static Volume ... + bool allowStaticVolume = staticVolume > 0; + + // + // Apply Dynamic Volume ... + bool aloowApplyDynamicVolume = useDynamicVolume && + dynamicVolumeStep && + dynamicVolumeBalanceFactor; + + // + // Apply Risk Per Trade Volume ... + bool allowApplyRiskPerTradeVolume = + !aloowApplyDynamicVolume && + riskPercentPerBalance > 0; + + // + // Apply Balance Per Trade Volume ... + bool allowApplyBalacePerTradeVolume = + !aloowApplyDynamicVolume && + !allowApplyRiskPerTradeVolume && + balancePerTrade > 0; + + // + // First Check Dynamic Volume ... + if (aloowApplyDynamicVolume) + { + // + // Dynamic Volume ... + double dVolume = mTrader.GetDynamicVolume( + signal.symbol, + dynamicVolumeBalanceFactor, + dynamicVolumeStep // + ); + if (dVolume < fVolume) + { + dVolume = fVolume; + } + + // + signal.volume = dVolume; + } + else if (allowApplyRiskPerTradeVolume) + { + // + double riskAmountPerBalance = (riskPercentPerBalance * balance) / 100; + + // + double risk = signal.GetRisk(); + double points = GetPoints(signal.symbol); + double riskInPoints = risk / points; + + // + double volume = mTrader.mAccount.CalculateVolume( + signal.symbol, + riskAmountPerBalance, + riskInPoints // + ); + if (volume <= 0) + { + volume = fVolume; + } + + // + // Check Dynamic Risk Management ... + bool allowDynamicRiskManagement = DynamicRiskManagement(); + if (allowDynamicRiskManagement) + { + // + // Calculate Dynamic Additional Risk Management Volume Multiplier ... + double mAdditionalRiskMultiplier = CalculateAdditionalVolumeMultiplier(signal); + if (mAdditionalRiskMultiplier < 1) + { + mAdditionalRiskMultiplier = 1; + } + + // + volume *= mAdditionalRiskMultiplier; + } + + // + signal.volume = volume; + } + else if (allowApplyBalacePerTradeVolume) + { + // + double risk = signal.GetRisk(); + double points = GetPoints(signal.symbol); + double riskInPoints = risk / points; + + // + double volume = mTrader.mAccount.CalculateVolume( + signal.symbol, + balancePerTrade, + riskInPoints // + ); + if (volume <= 0) + { + volume = fVolume; + } + + // + signal.volume = volume; + } + else if (allowStaticVolume) + { + signal.volume = staticVolume; + } + else + { + signal.volume = fVolume; + } + + // + // Normalize Signal Volume ... + signal.volume = NormalizeVolume( + signal.volume, + signal.symbol // + ); + } + + /** + * Configure Startegy ... + */ + void ConfigureStrategy(XCX121SMCBaseStrategy *&strategy) + { + // + if (strategy == NULL) + { + return; + } + + // + // Configure Alerts ... + strategy.SetAlertPrefix(GetTag()); + strategy.SetAlertLogAlerts(GetAlertLogAlerts()); + strategy.SetAlertMailAlerts(GetAlertMailAlerts()); + strategy.SetAlertPushAlerts(GetAlertPushAlerts()); + strategy.SetAlertEnableAlerts(GetAlertEnableAlerts()); + strategy.SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + // Confiugre Signalling ... + + // + strategy.R2R(R2R()); + strategy.AllowLong(AllowLong()); + strategy.AllowShort(AllowShort()); + strategy.MaxAllowedSpread(20); + // strategy.MaxAllowedSaveTicks(150); + // strategy.MinRequiredTicksForSpreadPass(100); + + // + if (Disabled()) + { + strategy.Disable(); + } + else + { + strategy.Enable(); + } + + // + } + + /** + * Register an Strategy in EA ... + * + * @param strategy: XCX121SMCBaseStrategy instance ... + */ + void RegisterStrategy(XCX121SMCBaseStrategy *strategy) + { + // + if (strategy == NULL) + { + return; + } + + // + ArrayResize( + mStrategies, + ArraySize(mStrategies) + 1 // + ); + + // + mStrategies[ArraySize(mStrategies) - 1] = strategy; + } + + /** + * Re Configure All Registered Strategies ... + */ + void ReConfigureAllStrategies() + { + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + ConfigureStrategy(mStrategies[i]); + } + } + + /** + * Re Configure Trade Handler ... + */ + void ReConfigureTradeHandler() + { + // + if (mTradeHandler == NULL) + { + return; + } + + // + // Configure Alerts ... + mTradeHandler.SetAlertPrefix(GetTag()); + mTradeHandler.SetAlertEnableAlerts(GetAlertEnableAlerts()); + mTradeHandler.SetAlertLogAlerts(GetAlertLogAlerts()); + mTradeHandler.SetAlertMailAlerts(GetAlertMailAlerts()); + mTradeHandler.SetAlertPushAlerts(GetAlertPushAlerts()); + mTradeHandler.SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + mTradeHandler.AllowLong(AllowLong()); + mTradeHandler.AllowShort(AllowShort()); + mTradeHandler.MaxAllowedLongs(MaxAllowedLongs()); + mTradeHandler.MaxAllowedShorts(MaxAllowedShorts()); + mTradeHandler.UseMaxAllowedSignalsPerSymbol(UseMaxAllowedSignalsPerSymbol()); + mTradeHandler.LastPositionProfitForAcceptNextInPoint(LastPositionProfitForAcceptNextInPoint()); + mTradeHandler.DelaysBetweenTwoSignalsInBar(DelaysBetweenTwoSignalsInBar()); + mTradeHandler.MaxAllowedSpread(MaxAllowedSpread()); + mTradeHandler.MaxAllowedDrawdownToOpenTrades(MaxAllowedDrawdownToOpenTrades()); + mTradeHandler.MaxAllowedSLToPauseSignallingPerSymbol(MaxAllowedSLToPauseSignallingPerSymbol()); + mTradeHandler.PauseSignallingAfterReachesMaxAllowedSLInSecconds(PauseSignallingAfterReachesMaxAllowedSLInSecconds()); + mTradeHandler.AllowHedging(AllowHedging()); + mTradeHandler.MinOpenTradesFroHedging(MinOpenTradesFroHedging()); + mTradeHandler.HedgingMinVolumeStep(HedgingMinVolumeStep()); + mTradeHandler.HedgeingMinRequiredProfitPerVolumeStep(HedgeingMinRequiredProfitPerVolumeStep()); + } + + // + private: + // + + // + // Props ... + + // + bool mShowCandles; // Show Candles ... + + // + // Signalling Props ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + int mMaxAllowedLongs; // Max Allowed Long Signals ... + int mMaxAllowedShorts; // Max Allowed Short Signals ... + bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ... + double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ... + int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ... + double mMaxAllowedSpread; // Max Allowed Spread for Signalling ... + int mMinRequiredVerificationForSpreadPass; // Minimum Spread Verification for Signalling ... + + // + // Trade ... + bool mAllowTrade; // Allow Open Trade On Signals ... + string mStartTradeAt; // Enable Trade on Signals on Time ... + string mStopTradeAt; // Enable Trade on Signals on Time ... + string mCloseAllTradesAt; // Enable Close All Trades on Signals on Time ... + + // + bool mIsForceCloseAtTime; + + // + // Risk Management Props ... + double mR2R; // Signallers Risk to Reward Ratio ... + double mVolume; // Static Volume ... + double mStaticBalance; // Static Balance for Calculate Trade Volume ... + double mBalancePerTrade; // Balance Used in Each Trade ... + double mRiskPercentPerBalance; // Risk Percent Per Balance in Each Trade ... + bool mDynamicRiskManagement; // Dynamic Risk Management ... + bool mUseDynamicVolume; // Use Dynamic Volume ... + double mDynamicVolumeStep; // Increase Volume Step ... + double mDynamicVolumeBalanceFactor; // Balance Factor for Generate Dynamic Volume ... + double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ... + int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ... + int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + + // + // Protection Props ... + bool mAllowHedging; // Allow Hedge Positions ... + int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ... + double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ... + double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ... + + // + double CalculateAdditionalVolumeMultiplier(XSignal &signal) + { + // + double result = 0; + + // + if (!signal.IsValid()) + { + return result; + } + + // + X121SMCSymbolPositionInfo info; + bool hasInfo = mTradeHandler.GetSymbolInfo( + signal.symbol, + info // + ); + if (!hasInfo) + { + return result; + } + + // + if (info.countedSLs >= 2) + { + result = (info.countedSLs / 2) + 1; + } + + // + return result; + } + + /** + * Handle Guard Actions ... + * + * @param guards: X121SMCGuard instance Collection ... + */ + void HandleGuards(X121SMCGuard &guards[]) + { + // + int count = ArraySize(guards); + if (!IsValidSize(guards)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + X121SMCGuard iGuard = guards[i]; + + // + if (!iGuard.IsValid()) + { + continue; + } + + // + // Here we Have to Handle Guard Actions ... + + // + // Close ... + bool canClose = + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE; + + // + // Close All ... + bool canCloseAll = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_ALL; + + // + // Close Longs ... + bool canCloseLongs = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_LONGS; + + // + // Close Shorts ... + bool canCloseShorts = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_SHORTS; + + // + // Partial Close ... + bool canPartialClose = + NotEmpty(iGuard.ticket) && + iGuard.volumeMultiplier > 0 && + iGuard.action == X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // + // Trail Stop ... + bool canTrailStop = + iGuard.sl > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + // Trail Target ... + bool canTrailTarget = + iGuard.tp > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_TARGET; + + // + // Hedge ... + bool canHedge = iGuard.action == X_121_SMC_GUARD_ACTION_HEDGE; + + // + // Check is Guard Valid ... + bool isValidGuardAction = + canHedge || + canClose || + canCloseAll || + canTrailStop || + canCloseLongs || + canTrailTarget || + canCloseShorts || + canPartialClose; + if (!isValidGuardAction) + { + continue; + } + + // + // Now we Sure to Have a Valid Guard ... + // Start to o Guard Actions ... + + // + // Close All ... + if (canCloseAll) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + string comment = "Guard Close All ..."; + string message = "Guard Close All (" + ToString(positionsCount) + ") Positions Successfully ..."; + int forceClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (forceClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Longs ... + if (canCloseLongs) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasLongPositions) + { + // + string comment = "Guard Close Longs ..."; + string message = "Guard Close (" + ToString(longPositionsCount) + ") Long Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + longPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Shorts ... + if (canCloseShorts) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasShortPositions) + { + // + string comment = "Guard Close Shorts ..."; + string message = "Guard Close (" + ToString(shortPositionsCount) + ") Short Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + shortPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close ... + if (canClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + XPosition positions[]; + AddRef( + iPosition, + positions // + ); + + // + string comment = "Guard Close ..."; + string message = "Guard Close " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Partial Close ... + if (canPartialClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + // Normalize Volume Multiplier ... + double vMult = iGuard.volumeMultiplier; + if (vMult > 0.5) + { + vMult = 0.5; + } + if (vMult < 0) + { + vMult = 0.5; + } + + // + // Calculate and Normalize Volume ... + double volume = iPosition.volume * iGuard.volumeMultiplier; + volume = NormalizeVolume( + volume, + iPosition.symbol // + ); + + // + string comment = "Guard Partially Closed: " + ToString(volume) + " ..."; + string message = "Guard Partially Closed " + (isLong ? "Long" : "Short") + ": " + ToString(volume) + " Successfully ..."; + bool isModified = mTrader.ClosePartial( + iPosition.ticket, + volume, + comment // + ); + if (isModified) + { + // + mTradeHandler.Alert(message); + + // + if (volume == iPosition.volume) + { + // + mTradeHandler.Finish( + iPosition.ticket, + iPosition, + comment // + ); + + // + RestEA(120 * 60); + } + } + } + } + + // + // Hedge ... + if (canHedge) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + int longs = 0; + double longProfits = 0; + double longVolumes = 0; + + // + int shorts = 0; + double shortProfits = 0; + double shortVolumes = 0; + CountPositions( + positions, + longs, + longProfits, + longVolumes, + shorts, + shortProfits, + shortVolumes // + ); + + // + int count = longs + shorts; + double profits = longProfits + shortProfits; + double volumes = longVolumes + shortVolumes; + + // + bool canDoHedge = + count > 0 && + profits > 0 && + volumes > 0; + if (canDoHedge) + { + // + string comment = "Guard Hedge ..."; + string message = "Guard Hedge (" + ToString(count) + ") Positions by: (" + ToString(profits) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + } + + // + // Trail Stop ... + if (canTrailStop) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iPosition.profit > 0 && + isLong + ? iPosition.price > iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl < iGuard.sl) + : iPosition.price < iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl > iGuard.sl); + if (canDoTrail) + { + // + string comment = "Guard Trail Stop ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Stop Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iGuard.sl, + iPosition.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + + // + // Trail Target ... + if (canTrailTarget) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iGuard.tp != iPosition.tp && + isLong + ? iGuard.tp > iPosition.price + : iGuard.tp < iPosition.price; + if (canDoTrail) + { + // + string comment = "Guard Trail Target ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Target Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iPosition.sl, + iGuard.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + } + + // + Clean(guards); + Clean(guards); + } + + // + void RestEA(int seconds) + { + // + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.guard.lib.ex5 b/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.guard.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..b6d7fc63d248c3193618c3961edf5c26f14729f7 GIT binary patch literal 17330 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 2) + // // { + // // // + // // lastBullishZone = bullishConsolidationZones[bullishConsolidationZonesCount - 1]; + // // prevLastBullishZone = bullishConsolidationZones[bullishConsolidationZonesCount - 2]; + + // // // + // // hasLastBullishBox = ToBox( + // // lastBullishBox, + // // lastBullishZone // + // // ); + // // hasPrevLastBullishBox = ToBox( + // // prevLastBullishBox, + // // prevLastBullishZone // + // // ); + + // // // + // // isLastBullishAbovePrev = hasLastBullishBox && + // // hasPrevLastBullishBox && + // // IsBoxAbove( + // // lastBullishBox, + // // prevLastBullishBox // + // // ); + + // // // + // // isLastBullishBelowPrev = hasLastBullishBox && + // // hasPrevLastBullishBox && + // // IsBoxBelow( + // // lastBullishBox, + // // prevLastBullishBox // + // // ); + // // } + + // // // + // // if (hasBearishConsolidationZones && + // // bearishConsolidationZonesCount >= 2) + // // { + // // // + // // lastBearishZone = bearishConsolidationZones[bearishConsolidationZonesCount - 1]; + // // prevLastBearishZone = bearishConsolidationZones[bearishConsolidationZonesCount - 2]; + + // // // + // // hasLastBearishBox = ToBox( + // // lastBearishBox, + // // lastBearishZone // + // // ); + // // hasPrevLastBearishBox = ToBox( + // // prevLastBearishBox, + // // prevLastBearishZone // + // // ); + + // // // + // // isLastBearishAbovePrev = hasLastBearishBox && + // // hasPrevLastBearishBox && + // // IsBoxAbove( + // // lastBearishBox, + // // prevLastBearishBox // + // // ); + + // // // + // // isLastBearishBelowPrev = hasLastBearishBox && + // // hasPrevLastBearishBox && + // // IsBoxBelow( + // // lastBearishBox, + // // prevLastBearishBox // + // // ); + // // } + + // // // + // // } + + // // + // // Detect High Probability Swings ... + // // bool isSwingLow = + // // // + // // cBar.low > pBar.low && + // // ppBar.low > pBar.low && + // // // + // // zBar.low > pBar.low + // // // + // // ; + // // bool isSwingHigh = + // // // + // // cBar.high < pBar.high && + // // ppBar.high < pBar.high && + // // // + // // zBar.high < pBar.high + // // // + // // ; + // // bool isStrongSwingLow = + // // pBar.IsBullish() && + // // pBar.GetLowShadow() >= pBar.GetBody() * 2; + // // bool isStrongSwingHigh = + // // pBar.IsBearish() && + // // pBar.GetHighShadow() >= pBar.GetBody() * 2; + + // // // + // // bool isStrongSwingLowAboveLastBullishBox = + // // isStrongSwingLow && + // // hasLastBullishBox && + // // pBar.low > lastBullishBox.upper; + + // // // + // // bool isStrongSwingHighBelowLastBearishBox = + // // isStrongSwingHigh && + // // hasLastBearishBox && + // // pBar.high < lastBearishBox.lower; + + // // + // // Here We Have all Requirements for Guarding Positions ... + + // // + // // Available Guards: + // // X_121_SMC_GUARD_ACTION_NONE + // // X_121_SMC_GUARD_ACTION_CLOSE + // // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // // X_121_SMC_GUARD_ACTION_HEDGE + + // // + // // X_121_SMC_GUARD_ACTION_CLOSE: + // // Close Specified Position on Specified Conditions ... + // if (!isColseIgnored) + // { + // // + // // TODO: + // // - [] Implement Close on Nearest on TP ... + // } + + // // + // // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // // Close All Positions on Specified Conditions ... + // if (!isColseAllIgnored) + // { + // // + // // TODO: + // // - [] Implement Close All Positions on Weekend ... + // } + + // // + // // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // // Close All Long Positions on Specified Conditions ... + // if (!isColseLongsIgnored) + // { + // // + // } + + // // + // // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // // Close All Short Positions on Specified Conditions ... + // if (!isColseShortsIgnored) + // { + // // + // } + + // // + // // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // // Partial Close Specified Position on Specified Conditions ... + // if (!isPartialColseIgnored) + // { + // // + // // Breake Even ... + // // Usually Break Even Works on TP2 Reached ... + // // when tp reached to required Level, we Close 50% of Entered Volume ... + // bool canBreakEven = breakEvenTPLevel >= 0; + + // // + // for (int i = 0; i < count; i++) + // { + // // + // XPosition iPosition = ownPositions[i]; + + // // + // bool isInProfit = iPosition.profit > 0; + + // // + // double reachedTPLevel = 0; + // double reachedTPPrice = 0; + // if (isInProfit) + // { + // // + // iPosition.CalculateReahedTP( + // reachedTPLevel, + // reachedTPPrice // + // ); + // } + + // // + // // Break Event ... + // if (canBreakEven) + // { + // // + // // Position Must be In Profit ... + // if (!isInProfit) + // { + // continue; + // } + + // // + // bool canDoBreakEven = reachedTPLevel == breakEvenTPLevel && + // reachedTPPrice > 0; + // if (canDoBreakEven) + // { + // // + // X121SMCGuard iGuard; + + // // + // iGuard.time = cTime; + // iGuard.symbol = symbol; + // iGuard.provider = provider; + // iGuard.action = X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // // + // iGuard.ticket = iPosition.ticket; + + // // + // iGuard.volumeMultiplier = 0.5; + + // // + // AddGuard( + // iGuard, + // guards // + // ); + // } + // } + // } + // } + + // // + // // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // // Trail Stop Specified Position on Specified Conditions ... + // if (!isTrailStopIgnored) + // { + // // + // for (int i = 0; i < count; i++) + // { + // // + // XPosition iPosition = ownPositions[i]; + + // // + // bool isLong = IsLong(iPosition.type); + // bool isInProfit = iPosition.profit > 0; + + // // + // double reachedTPLevel = 0; + // double reachedTPPrice = 0; + // if (isInProfit) + // { + // // + // iPosition.CalculateReahedTP( + // reachedTPLevel, + // reachedTPPrice // + // ); + // } + + // // + // // Trai Stop ... + // if (!isInProfit) + // { + // continue; + // } + + // // + // double trailedStop = 0; + + // // + // // Trail Stop Senarios ... + // // - occures two same type consolidation zones in order of positions type; + // // - occures a swing in order of consolidation zones ... + + // // // + // // bool canTrailBasedOnTwoZone = + // // isLong + // // ? isLastBullishAbovePrev + // // : isLastBearishBelowPrev; + // // if (canTrailBasedOnTwoZone) + // // { + // // // + // // trailedStop = + // // isLong + // // ? prevLastBullishBox.lower + // // : prevLastBearishBox.upper; + // // } + + // // // + // // bool canTrailBasedOnZoneSwing = + // // trailedStop <= 0 && + // // (isLong + // // ? isStrongSwingLowAboveLastBullishBox + // // : isStrongSwingHighBelowLastBearishBox); + // // if (canTrailBasedOnZoneSwing) + // // { + // // // + // // trailedStop = + // // isLong + // // ? pBar.low + // // : pBar.high; + // // } + + // // // + // // bool canDoTrailStop = + // // trailedStop > 0 && + // // ( + // // // + // // iPosition.sl == 0 + // // ? (isLong + // // ? trailedStop > iPosition.entry && + // // trailedStop < iPosition.price + // // : trailedStop < iPosition.entry && + // // trailedStop > iPosition.price) + // // : (isLong + // // ? trailedStop > iPosition.sl && + // // trailedStop > iPosition.entry && + // // trailedStop < iPosition.price + // // : trailedStop < iPosition.sl && + // // trailedStop < iPosition.entry && + // // trailedStop > iPosition.price) + // // // + // // ) + // // // + // // ; + + // // // + // // if (canDoTrailStop) + // // { + // // // + // // X121SMCGuard iGuard; + + // // // + // // iGuard.time = cTime; + // // iGuard.symbol = symbol; + // // iGuard.provider = provider; + // // iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // // // + // // iGuard.ticket = iPosition.ticket; + + // // // + // // iGuard.sl = trailedStop; + + // // // + // // AddGuard( + // // iGuard, + // // guards // + // // ); + // // } + // } + // } + + // // + // // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // // Trail Target Specified Position on Specified Conditions ... + // if (!isTrailTargetIgnored) + // { + // // + // } + + // // + // // X_121_SMC_GUARD_ACTION_HEDGE: + // // Hedge all Positions on Specified Conditions ... + // if (!isHedgeIgnored) + // { + // // + // } + + // // + // // Cleanup Collections ... + + // // + // Clean(ownPositions); + // Clean(ownLongPositions); + // Clean(ownShortPositions); + + // // + // zBar.Clean(); + // cBar.Clean(); + // pBar.Clean(); + // ppBar.Clean(); + + // // + // Clean(visionPoiEvents); + // Clean(analysePoiEvents); + // Clean(visionCycleEvents); + // Clean(decisionPoiEvents); + // Clean(analyseCycleEvents); + // Clean(decisionCycleEvents); + // Clean(consolidationPoiEvents); + // Clean(consolidationCycleEvents); + + // // + // visionState.Clean(); + // analyseState.Clean(); + // decisionState.Clean(); + // visionConditions.Clean(); + // analyseConditions.Clean(); + // visionXConditions.Clean(); + // decisionConditions.Clean(); + // consolidationState.Clean(); + // analyseXConditions.Clean(); + // decisionXConditions.Clean(); + // consolidationConditions.Clean(); + // consolidationXConditions.Clean(); + + // // + // // lastBullishBox.Clean(); + // // lastBearishBox.Clean(); + // // lastBullishZone.Clean(); + // // lastBearishZone.Clean(); + // // prevLastBullishBox.Clean(); + // // prevLastBearishBox.Clean(); + // // prevLastBullishZone.Clean(); + // // prevLastBearishZone.Clean(); + + // // + // count = ArraySize(guards); + // result = IsValidSize(count); + + // + return result; +} diff --git a/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.ex5 b/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..ee6987998a89eb7311bc5ea4a8359653adc5b628 GIT binary patch literal 16286 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 literal 0 HcmV?d00001 diff --git a/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.mq5 b/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.mq5 new file mode 100644 index 0000000..b411b86 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -0,0 +1,737 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: X121SMCLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.base.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../../Helpers/x-saherelm.x121.helper.mq5" +#include "../../Libraries/x-saherelm.common.lib.mq5" +#include "../../Libraries/x-saherelm.x-poi.extensions.lib.mq5" +#include "../../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +const string X121SMCStrategyToken = "X121SMC"; + +// +const string X121SMCXWZToken = "X121XWZ"; + +// +// X121 SMC Providers ... +enum ENUM_X_121_SMC_PROVIDERS +{ + // + X_121_SMC_PROVIDER_NONE, + X_121_SMC_PROVIDER_XWZ, +}; + +// +// Guard Actions ... +enum ENUM_X_121_SMC_GUARD_ACTIONS +{ + X_121_SMC_GUARD_ACTION_NONE, // Nothing to Do + X_121_SMC_GUARD_ACTION_CLOSE, // Close Specified Position + X_121_SMC_GUARD_ACTION_CLOSE_ALL, // Close All Positions + X_121_SMC_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions + X_121_SMC_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position + X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position + X_121_SMC_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position + X_121_SMC_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position + X_121_SMC_GUARD_ACTION_HEDGE, // Hedge Specified Positions +}; + +// +// Each Market Cycle (Time Frame) Conditions +// Model as this Structure ... +struct X121SMCCycleConditions +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + XPOIState state; + X121Conditions x121Conditions; + + // + void X121SMCStrategyConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + time = NULL; + + // + state.Clean(); + x121Conditions.Clean(); + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + // + ; + + // + return result; + } + + // + // Reporter Functions ... + + /** + * Generate Provided Scores ... + * + * @param bullishScore: Integer, reference ... + * @param bearishScore: Integer, referenceF ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + if (!IsValid()) + { + return; + } + + // + double bullScore = 0; + double bearScore = 0; + } + + /** + * Generate Summary ... + * + * @param onlyCommons: Boolean ... + * @param onlyConditions: Boolean ... + * @param includeScores: Boolean ... + * @param ignoreFalseConditions: Boolean ... + * @param separator: String ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores, + true // + ); + + // + string conditionsStr = + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + "----------" + separator + + (onlyConditions + ? "" + : commonStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Get Unique Identifier ... + * + * @param forObject: Boolean ... + * + * @return ( string ) + */ + string GetTag( + bool forObject = false // + ) + { + // + string result = NULL; + + // + string typeName = GetTypeName(this); + + // + if (!forObject) + { + result = typeName; + } + else + { + // + result = typeName + "_" + + symbol + "_" + ToString(period) + "_" + + ToMD5(time); + } + + // + return result; + } + + // +}; + +// +// Model Signalling Conditions ... +struct X121SMCStrategyConditions +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + double sl; + double tp; + string provider; + double targets[]; + ENUM_X_DIRECTION signalDir; + + // + void X121SMCStrategyConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + symbol = NULL; + period = NULL; + + // + sl = 0; + tp = 0; + provider = NULL; + signalDir = X_DIRECTION_NONE; + + // + Clean(targets); + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + + // + return result; + } + + /** + * Check Conditions Has Valid Bullish Signal ... + * + * @return ( bool ) + */ + bool HasBullishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(signalDir); + if (!result) + { + return result; + } + + // + result = + IsBullish(signalDir); + + // + return result; + } + + /** + * Check Conditions Has Valid Bearish Signal ... + * + * @return ( bool ) + */ + bool HasBearishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(signalDir); + if (!result) + { + return result; + } + + // + result = + IsBearish(signalDir); + + // + return result; + } + + // + // Reporter Functions ... + + /** + * Generate Provided Scores ... + * + * @param bullishScore: Integer, reference ... + * @param bearishScore: Integer, referenceF ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + if (!IsValid()) + { + return; + } + + // + double bullScore = 0; + double bearScore = 0; + } + + /** + * Generate Summary ... + * + * @param onlyCommons: Boolean ... + * @param onlyConditions: Boolean ... + * @param includeScores: Boolean ... + * @param ignoreFalseConditions: Boolean ... + * @param separator: String ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores, + true // + ); + + // + string conditionsStr = + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + "----------" + separator + + (onlyConditions + ? "" + : commonStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Get Unique Identifier ... + * + * @param forObject: Boolean ... + * + * @return ( string ) + */ + string GetTag( + bool forObject = false // + ) + { + // + string result = NULL; + + // + string typeName = GetTypeName(this); + + // + if (!forObject) + { + result = typeName; + } + else + { + // + result = typeName + "_" + + symbol + "_" + ToString(period) + "_" + + ToMD5(time); + } + + // + return result; + } + + // +}; + +// +// Model a Guard Action ... +struct X121SMCGuard +{ + // + // Props ... + ENUM_X_121_SMC_GUARD_ACTIONS action; + datetime time; + + // + string symbol; + string provider; + + // + // Specified Position ... + ulong ticket; + + // + // Partial Close ... + double volumeMultiplier; + + // + // SL Trial ... + double sl; + + // + // TP Trial ... + double tp; + + // + // Constructor ... + X121SMCGuard() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + action = X_121_SMC_GUARD_ACTION_NONE; + + // + symbol = NULL; + provider = NULL; + + // + ticket = 0; + + // + volumeMultiplier = 0; + + // + sl = 0; + tp = 0; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(time) && + IsValid(symbol) && + IsValid(provider) && + action != X_121_SMC_GUARD_ACTION_NONE + // + ; + if (!result) + { + return result; + } + + // + // Validate Model Based On Specified Guard Actions ... + + // + return result; + } +}; + +/** + * Add Guard to Collection ... + * + * @param guard: X121SMCGuard instance ... + * @param guards: X121SMCGuard instance Collection ... + * + * @return ( int ) + */ +int AddGuard( + X121SMCGuard &guard, + X121SMCGuard &guards[] // +) +{ + // + int result = 0; + + // + if (!guard.IsValid()) + { + return result; + } + + // + AddRef( + guard, + guards // + ); + + // + result = ArraySize(guards); + + // + return result; +} + +// +// +// + +typedef void (*TOnX121SMCSignal)( + XSignal &signal, + X121SMCStrategyConditions &conditions // +); + +// +// Extentions ... + +/** + * Validate a Signal Provider ... + * + * @param value: ENUM_X_121_SMC_PROVIDERS member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_121_SMC_PROVIDERS value) +{ + // + bool result = false; + + // + result = value != X_121_SMC_PROVIDER_NONE; + + // + return result; +} + +/** + * Converts a Signal Provider to String ... + * + * @param value: ENUM_X_121_SMC_PROVIDERS member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_121_SMC_PROVIDERS value) +{ + // + string result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + switch (value) + { + // + case X_121_SMC_PROVIDER_XWZ: + result = X121SMCXWZToken; + break; + } + + // + return result; +} + +/** + * Parse Specified String as a Signal Provider ... + * + * @param value: String ... + * + * @return ( ENUM_X_121_SMC_PROVIDERS ) + */ +ENUM_X_121_SMC_PROVIDERS ParseProvider(string value) +{ + // + ENUM_X_121_SMC_PROVIDERS result = X_121_SMC_PROVIDER_NONE; + + // + if (!IsValid(value)) + { + return result; + } + + // + if (Contains(X121SMCXWZToken, value)) + { + result = X_121_SMC_PROVIDER_XWZ; + } + + // + return result; +} + +// diff --git a/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.class.ex5 b/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4773c5c5a5e34b00385eabd180c9e8c2be89cd04 GIT binary patch literal 16196 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 maxAllowedSLDistanceInPoint) + { + // Print("Max Aloowed Risk Point Reached ..."); + } + + // + double reward2 = 2 * risk; + double reward3 = 3 * risk; + double iTP2 = isBullish + ? entry + reward2 + : entry - reward2; + double iTP3 = isBullish + ? entry + reward3 + : entry - reward3; + + // + Add( + iTP3, + targets // + ); + + // + // Based On Priority ... + has = priority != X121SMC_XWZ_PRIORITY_NONE; + if (has) + { + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + } + break; + + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + if (isBullish) + { + // + // Weak ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Strong High ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + } + else + { + // + // Weak ... + Add( + workingZone.demandZone.Upper(), + targets // + ); + + // + // Low ... + Add( + workingZone.quarter3, + targets // + ); + + // + // Regular ... + Add( + workingZone.quarter2, + targets // + ); + + // + // High ... + Add( + workingZone.quarter1, + targets // + ); + + // + // Strong High ... + Add( + workingZone.supplyZone.Lower(), + targets // + ); + } + break; + } + } + } + + // + // Summarize Results ... + result = hasPriority && + hasSignalBox && + hasRewardAmount; + + // + if (result) + { + // + Copy( + sls, + mConditions.sls // + ); + Copy( + targets, + mConditions.targets // + ); + + // + mConditions.sl = sl; + mConditions.pivot = pivot; + mConditions.point = point; + mConditions.reward = reward; + mConditions.setupTime = cTime; + mConditions.dir = signalBoxDir; + mConditions.priority = priority; + mConditions.signalBox = signalBox; + mConditions.provider = signalProvider; + mConditions.amountPercent = amountPercent; + } + + // + // + // + + // + // Cleanup Resources ... + + // + Clean(sls); + Clean(targets); + + // + provider.Clean(); + + // + signalBox.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Detect Trigger Conditions ... + bool DetectSignalTrigger( + // + X121SMCStrategyXWZSignalConditions &conditions, + // + X121SMCStrategySignalProviderData &provider, + // + int maxAllowedSetupAge = 60 + // + ) + { + // + bool result = false; + + // + result = + // + provider.IsValid() + // + ; + if (!result) + { + return result; + } + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + result = provider.Prepare( + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + double iAtr = provider.decisionXConditions.atrBuffer[1]; + iAtr *= 1.5; + + // + // Check Signal Validation ... + // IMPORTANT: since all Validations done in SetUp Process ... + // here we only Execute Signal ... + + // + result = isBullish || + isBearish; + + // + if (result) + { + // + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + } + + // + // Cleanup ... + + // + provider.Clean(); + + // + return result; + } + + // + // Detect Guards ... + bool DetectGuards( + // + X121SMCGuard &guards[], + const XPosition &positions[], + // + X121SMCStrategySignalProviderData &provider + // + ) + { + // + bool result = false; + + // + Clean(guards); + + // + // Set Provider for Common Guards ... + string signalProvider = ToString(X_121_SMC_PROVIDER_XWZ); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL cBar; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + result = provider.IsValid(); + result = + result && + provider.Prepare( + zIndex, + loopback // + ); + if (!result) + { + // + provider.Clean(); + return result; + } + + // + // Select Own Positions ... + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + signalProvider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + // Check Extracted Positions ... + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + // Validate Own Positions ... + result = IsValidSize(count); + if (!result) + { + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + return result; + } + + // + // + // + + // + // Get Global and Common Guards ... + + // + // ENUM_X_121_SMC_GUARD_ACTIONS ignoreGuards[1] = { + // X_121_SMC_GUARD_ACTION_TRAIL_STOP // + // }; + // result = DetectX121SMCGuards( + // signalProvider, + // guards, + // positions, + // provider, + // // + // ignoreGuards + // // + // ); + + // + // + // + + // + // Implement Custom Implemented Guards ... + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Selected Consolidation Zones ... + + // + int idx = -1; + bool has = false; + + // + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + has = provider.decisionState.HasBullishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(provider.decisionState.bullishConsolidationZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + bullishConsolidationZone = provider.decisionState.bullishConsolidationZones[idx]; + } + } + + // + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + has = provider.decisionState.HasBearishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(provider.decisionState.bearishConsolidationZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + bearishConsolidationZone = provider.decisionState.bearishConsolidationZones[idx]; + } + } + + // + XBoxZone bullishBox; + bool hasBullishBox = false; + bool isBullishBoxBreaked = false; + if (!hasBullishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bullishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bullishOrderBlocks[idx]; + + // + hasBullishBox = ToBox( + bullishBox, + ob // + ); + } + + // + if (!hasBullishBox) + { + bullishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + XBoxZone bearishBox; + bool hasBearishBox = false; + bool isBearishBoxBreaked = false; + if (!hasBearishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bearishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bearishOrderBlocks[idx]; + + // + hasBearishBox = ToBox( + bearishBox, + ob // + ); + } + + // + if (!hasBearishBox) + { + bearishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Available Guards: + // X_121_SMC_GUARD_ACTION_NONE + // X_121_SMC_GUARD_ACTION_CLOSE + // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // X_121_SMC_GUARD_ACTION_HEDGE + + // + // X_121_SMC_GUARD_ACTION_CLOSE: + // Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // Close All Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // Close All Long Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // Close All Short Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // Partial Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // Trail Stop Specified Position on Specified Conditions ... + bool handleStoptrailingBasedOnBoxes = true; + bool handleStoptrailingBasedOnConsolidationZones = true; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + bool isInited = cBar.Init( + iPosition.symbol, + iPosition.period, + cIndex // + ); + + // + isBullishBoxBreaked = + isInited && + hasBullishBox && + cBar.high < bullishBox.lower; + + // + isBearishBoxBreaked = + isInited && + hasBearishBox && + cBar.low > bearishBox.upper; + + // + bool isLong = IsLong(iPosition.type); + bool isInProfit = iPosition.profit > 0; + + // + double sl = iPosition.sl; + double tp = iPosition.tp; + + // + // Trail Stops Using Consolidation Zones ... + + // + bool canTraiLonglUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (isLong && + isInProfit && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > iPosition.sl && + bullishConsolidationZone.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingCZone) + { + sl = bullishConsolidationZone.lower; + } + + // + bool canTraiShortlUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (!isLong && + isInProfit && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < iPosition.sl && + bearishConsolidationZone.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingCZone) + { + sl = bearishConsolidationZone.upper; + } + + // + bool canTrailUsingCZone = + canTraiLonglUsingCZone || + canTraiShortlUsingCZone; + + // + // Trail Stop Using Boxes ... + + // + bool canTraiLonglUsingBox = + // + handleStoptrailingBasedOnBoxes && + // + (isLong && + isInProfit && + hasBullishBox && + bullishBox.lower > iPosition.sl && + bullishBox.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingBox) + { + sl = bullishBox.lower; + } + + // + bool canTraiShortlUsingBox = + // + handleStoptrailingBasedOnBoxes && + // + (!isLong && + isInProfit && + hasBearishBox && + bearishBox.upper < iPosition.sl && + bearishBox.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingBox) + { + sl = bearishBox.upper; + } + + // + bool canTrailUsingBox = + canTraiLonglUsingBox || + canTraiShortlUsingBox; + + // + bool canTraiLonglUsingBreakedBox = + // + handleStoptrailingBasedOnBoxes && + // + (isLong && + isInProfit && + isBearishBoxBreaked && + bearishBox.upper > iPosition.sl && + bearishBox.upper > iPosition.entry) + // + ; + if (canTraiLonglUsingBreakedBox) + { + sl = bearishBox.upper; + } + + // + bool canTraiShortlUsingBreakedBox = + // + handleStoptrailingBasedOnBoxes && + // + (!isLong && + isInProfit && + isBullishBoxBreaked && + bullishBox.lower < iPosition.sl && + bullishBox.lower < iPosition.entry) + // + ; + if (canTraiShortlUsingBreakedBox) + { + sl = bullishBox.lower; + } + + // + bool canTrailUsingBreakedBox = + canTraiLonglUsingBreakedBox || + canTraiShortlUsingBreakedBox; + + // + // Summarize SL ... + + // + bool isSLPassed = + sl > 0 && + (isLong + ? iPosition.price - sl >= points * 15 + : sl - iPosition.price >= points * 15); + + // + bool canTrail = + isSLPassed && + (canTrailUsingBox || + canTrailUsingCZone || + canTrailUsingBreakedBox); + if (canTrail) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = signalProvider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.ticket = iPosition.ticket; + + // + iGuard.sl = sl; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // Trail Target Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_HEDGE: + // Hedge all Positions on Specified Conditions ... + + // + // Cleanup Collections ... + + // + cBar.Clean(); + + // + provider.Clean(); + + // + bullishBox.Clean(); + bearishBox.Clean(); + + // + bullishConsolidationZone.Clean(); + bearishConsolidationZone.Clean(); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + // + // Add Conditions to Conditions Collection ... + int AddConditionsIfNotExists( + int maxAllowed = 10 // + ) + { + // + int result = 0; + + // + bool isSetuped = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(mConditionsCollection); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXWZSignalConditions tmpItems[]; + Copy( + mConditionsCollection, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(mConditions.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXWZSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = mConditions.dir == iItem.dir && + mConditions.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + mConditionsCollection, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + mConditions, + mConditionsCollection // + ); + + // + // Remove Olds ... + CleanupArray( + mConditionsCollection, + maxAllowed // + ); + + // + result = ArraySize(mConditionsCollection); + + // + return result; + } + + // + // Draw Functions ... + // + + // + void DrawBar( + XOHCL &bar, + XCPOIDrawer *drawer, + bool forceClean = true // + ) + { + // + if (forceClean) + { + mBarObjects.Clear(); + } + + // + if (drawer == NULL || + !bar.IsValid()) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + + // + int widthBar = 2; + bool fillShadowsBar = true; + ENUM_LINE_STYLE styleBar = STYLE_SOLID; + color clrBar = + isBullish + ? clrAqua + : clrMagenta; + + // + datetime to = bar.NextAt(); + + // + XCOHCLObject *iObj; + bool isCreated = drawer + .CreateBar( + bar, + iObj, + to // + ); + if (isCreated) + { + // + iObj.BarSpes( + widthBar, + clrBar, + styleBar // + ); + + // + iObj.LowShadowFill(fillShadowsBar); + iObj.HighShadowFill(fillShadowsBar); + + // + mBarObjects.Add(iObj); + } + } + + // + protected: + // + + // + private: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + CArrayObj mObjects; + CArrayObj mBarObjects; + CArrayObj mWorkingZoneObjects; + + /** + * Initialize ... + */ + void Init() + { + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + mConditions.Clean(); + workingZone.Clean(); + Clean(mConditionsCollection); + + // + mBarObjects.Clear(); + } + + /** + * Update To Time of Exists Components ... + * + * @param value: updated time ... + */ + void UpdateTo( + datetime value = NULL // + ) + { + // + value = NormalizeTime(value); + + // + workingZone.UpdateTo(value); + } + + // + // Helpers ... + + // + bool CalculateRiskReward( + ENUM_X121SMC_XWZ_PRIORITY priority, + double &reward, + double &amountPercent // + ) + { + // + bool result = false; + + // + reward = 0; + amountPercent = 0; + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE; + if (!result) + { + return result; + } + + // + switch (priority) + { + // + case X121SMC_XWZ_PRIORITY_STRONG_HIGH: + // + reward = 6; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_HIGH: + // + reward = 4; + amountPercent = 2; + break; + + // + case X121SMC_XWZ_PRIORITY_REGULAR: + // + reward = 3; + amountPercent = 1.5; + break; + + // + case X121SMC_XWZ_PRIORITY_LOW: + // + reward = 2; + amountPercent = 1; + break; + + // + case X121SMC_XWZ_PRIORITY_WEAK: + // + reward = 1; + amountPercent = 0.5; + break; + } + + // + result = + // + reward > 0 && + amountPercent > 0 + // + ; + + // + return result; + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.ex5 b/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4da0c5b25032bb2e408e2d7e8e63ab7d37c639e9 GIT binary patch literal 17958 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 G+Hahn)z-ZL literal 0 HcmV?d00001 diff --git a/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.mq5 b/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.mq5 new file mode 100644 index 0000000..9ff3873 --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Signals/x-121.smc.xwz.signal.lib.mq5 @@ -0,0 +1,3034 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XWZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +enum ENUM_X121SMC_XWZ_PROVIDERS +{ + X121SMC_XWZ_PROVIDER_NONE, + X121SMC_XWZ_PROVIDER_ACTIVATED_MA, + X121SMC_XWZ_PROVIDER_ACTIVATED_BOX, + X121SMC_XWZ_PROVIDER_ACTIVATED_AREA, + X121SMC_XWZ_PROVIDER_ACTIVATED_ZONE, +}; + +// +enum ENUM_X121SMC_XWZ_PRIORITY +{ + X121SMC_XWZ_PRIORITY_NONE, + X121SMC_XWZ_PRIORITY_WEAK, + X121SMC_XWZ_PRIORITY_LOW, + X121SMC_XWZ_PRIORITY_REGULAR, + X121SMC_XWZ_PRIORITY_HIGH, + X121SMC_XWZ_PRIORITY_STRONG_HIGH, +}; + +// +// Definitions ... + +// +struct X121SMCStrategyXWZWorkingZone +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double quarter1; + double quarter2; + double quarter3; + + // + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + + // + XOBFVG waitingZones[]; + XOBFVG unavailableZones[]; + + // + XBoxZone waitingBoxes[]; + XBoxZone unavailableBoxes[]; + + // + CArrayObj mDrawnObjects; + CArrayObj mWorkingZoneObjects; + + // + // Constructor ... + X121SMCStrategyXWZWorkingZone() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + quarter1 = 0; + quarter2 = 0; + quarter3 = 0; + + // + symbol = NULL; + period = NULL; + + // + Clean(waitingZones); + Clean(unavailableZones); + + // + Clean(waitingBoxes); + Clean(unavailableBoxes); + + // + ZeroMemory(supplyZone); + ZeroMemory(demandZone); + + // + mDrawnObjects.Clear(); + mWorkingZoneObjects.Clear(); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + // + quarter1 > 0 && + quarter2 > 0 && + quarter3 > 0 && + HasSupplyZone() && + HasDemandZone() && + quarter1 > quarter2 && + quarter2 > quarter3 + // + ; + + // + return result; + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + int barIndex, + X121SMCStrategySignalProviderData &provider // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + // + provider.IsValid() + // + ; + if (!result) + { + return result; + } + + // + symbol = _symbol; + period = _period; + + // + int idx = -1; + int count = 0; + bool has = false; + + // + XOHCL zBar; + has = zBar.Init( + symbol, + period, + barIndex // + ); + result = has; + if (!result) + { + zBar.Clean(); + return result; + } + double ll5 = zBar.FindLowest(5, MODE_LOW); + double hh5 = zBar.FindHighest(5, MODE_HIGH); + zBar.Clean(); + + // + // Supply Zone ... + has = HasSupplyZone(); + if (!has) + { + // + idx = GetHighest(provider + .consolidationState + .supplyZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + supplyZone = provider + .consolidationState + .supplyZones[idx]; + has = hh5 < supplyZone.Lower(); + if (!has) + { + supplyZone = NULL; + } + } + } + + // + // Demand Zone ... + has = HasDemandZone(); + if (!has) + { + // + idx = GetLowest(provider + .consolidationState + .demandZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + demandZone = provider + .consolidationState + .demandZones[idx]; + has = ll5 > demandZone.Upper(); + if (!has) + { + demandZone = NULL; + } + } + } + + // + if (supplyZone != NULL && + demandZone != NULL && + supplyZone.IsValid() && + demandZone.IsValid()) + { + // + double upper = supplyZone.Lower(); + double lower = demandZone.Upper(); + + // + double delta = ((upper - lower) / 100) * 25; + + // + quarter1 = upper - (1 * delta); + quarter2 = upper - (2 * delta); + quarter3 = upper - (3 * delta); + } + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + // + bool DetectZone( + X121SMCStrategySignalProviderData &provider // + ) + { + // + bool result = false; + + // + result = IsValid() && + provider.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + int count = 0; + bool has = false; + datetime cTime = TimeCurrent(); + + // + XOBFVG obFVG; + XBoxZone obBox; + XBoxZone fvgBox; + XBoxZone supplyBox; + XBoxZone demandBox; + + // + XCFVG *fvg = NULL; + XCOrderBlock *ob = NULL; + XCSupplyZone *supply = NULL; + XCDemandZone *demand = NULL; + + // + // Check New Supply Zone Detection ... + bool hasNewSupply = + Contains( + X_SUPPLY_ZONE_DETECTED, + provider.consolidationPoiEvents // + ); + if (hasNewSupply) + { + // + idx = GetYoungest(provider + .consolidationState + .supplyZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + supply = provider + .consolidationState + .supplyZones[idx]; + has = ToBox( + supplyBox, + supply // + ); + if (has) + { + // + supply.To(cTime); + supplyBox.to = cTime; + hasNewSupply = supplyBox.IsValid(); + } + } + } + + // + // Check New Demand Zone Detection ... + bool hasNewDemand = + Contains( + X_DEMAND_ZONE_DETECTED, + provider + .consolidationPoiEvents // + ); + if (hasNewDemand) + { + // + idx = GetYoungest(provider + .consolidationState + .demandZones // + ); + has = IsValidIndex(idx); + if (has) + { + // + demand = provider + .consolidationState + .demandZones[idx]; + has = ToBox( + demandBox, + demand // + ); + if (has) + { + // + demand.To(cTime); + demandBox.to = cTime; + hasNewDemand = demandBox.IsValid(); + } + } + } + + // + // Check New Fair Value Gap Detection ... + bool hasNewFairValueGap = + Contains( + X_BULLISH_FVG_DETECTED, + provider + .analysePoiEvents // + ) || + Contains( + X_BEARISH_FVG_DETECTED, + provider + .analysePoiEvents // + ); + if (hasNewFairValueGap) + { + // + idx = GetYoungest(provider + .analyseState + .fairValueGaps // + ); + has = IsValidIndex(idx); + if (has) + { + // + fvg = provider + .analyseState + .fairValueGaps[idx]; + has = ToBox( + fvgBox, + fvg // + ); + if (has) + { + // + fvg.To(cTime); + fvgBox.to = cTime; + hasNewFairValueGap = fvgBox.IsValid(); + } + } + } + + // + // Check New Order Block Detection ... + bool hasNewOrderBlock = + Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + provider + .consolidationPoiEvents // + ) || + Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + provider + .consolidationPoiEvents // + ); + if (hasNewOrderBlock) + { + // + idx = GetYoungest(provider + .consolidationState + .orderBlocks // + ); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider + .consolidationState + .orderBlocks[idx]; + has = ToBox( + obBox, + ob // + ); + if (has) + { + // + ob.To(cTime); + obBox.to = cTime; + hasNewOrderBlock = obBox.IsValid(); + } + } + } + + // + // Detect OB FVG ... + if (hasNewOrderBlock) + { + // + XOHCL obStartedBar; + bool isOBStartedBodyOut = false; + bool isOBStarted = ob.IsStarted( + ob.GetDirection(), + obStartedBar, + isOBStartedBodyOut // + ); + + // + has = isOBStarted; + if (has) + { + // + obFVG.ob = ob; + + // + // Select FVGs ... + count = provider + .analyseState + .CountFairValueGaps(); + has = IsValidSize(count); + if (!has) + { + obFVG.Clean(); + } + else + { + // + // Select FVG ... + for (int i = 0; i < count; i++) + { + // + XCFVG *iFVG = provider + .analyseState + .fairValueGaps[i]; + bool isBullish = iFVG.IsBullish(); + + // + XOHCL iStartedBar; + bool isBodyOut = false; + bool isStarted = iFVG.IsStarted( + iFVG.GetDirection(), + iStartedBar, + isBodyOut // + ); + iStartedBar.Clean(); + + // + bool isKindPassed = isStarted && + isBodyOut; + bool isSameDir = iFVG.GetDirection() == ob.GetDirection(); + bool isFromPassed = iFVG.From() >= obStartedBar.time; + bool isPlacePassed = + // + IsInsideOrDiff( + iFVG, + ob // + ) + // + // || + // // + // (isBullish + // ? IsAboveDiff( + // iFVG, + // ob, + // true // Ignore Inside ... + // ) + // : IsBelowDiff( + // iFVG, + // ob, + // true // Ignore Inside ... + // ) + // // + // ) + // + ; + + // + has = isSameDir && + isKindPassed && + isFromPassed && + isPlacePassed; + if (has) + { + obFVG.AddFVG(iFVG); + } + + // + ZeroMemory(iFVG); + } + } + } + + // + has = obFVG.IsValid(); + if (has) + { + // + has = IsExists(obFVG); + if (!has) + { + // + // New Waiting Zone ... + AddRef( + obFVG, + waitingZones // + ); + } + else + { + // + // Check Item Is not Exists ... + idx = FindIndex( + obFVG, + waitingZones // + ); + has = !IsValidIndex(idx); + if (!has) + { + // + // Update Exists Waiting Zone ... + waitingZones[idx].AddFVG(fvg); + } + } + } + + // + obFVG.Clean(); + obStartedBar.Clean(); + } + + // + // + // + + // + bool lookingOthers = false; + if (lookingOthers) + { + // + // Check New Order Block Detection Analyse ... + XBoxZone analyseOBBox; + XCOrderBlock *analyseOB = NULL; + bool hasNewAnalyseOrderBlock = + Contains( + X_BULLISH_ORDERBLOCK_DETECTED, + provider + .analysePoiEvents // + ) || + Contains( + X_BEARISH_ORDERBLOCK_DETECTED, + provider + .analysePoiEvents // + ); + if (hasNewAnalyseOrderBlock) + { + // + idx = GetYoungest(provider + .analyseState + .orderBlocks // + ); + has = IsValidIndex(idx); + if (has) + { + // + analyseOB = provider + .analyseState + .orderBlocks[idx]; + has = ToBox( + analyseOBBox, + analyseOB // + ); + if (has) + { + // + analyseOB.To(cTime); + analyseOBBox.to = cTime; + hasNewAnalyseOrderBlock = analyseOBBox.IsValid(); + } + } + } + + // + // Checking Analyse Order Block ... + if (hasNewAnalyseOrderBlock) + { + // + XOHCL obStartedBar; + bool isOBStartedBodyOut = false; + bool isOBStarted = analyseOB.IsStarted( + analyseOB.GetDirection(), + obStartedBar, + isOBStartedBodyOut // + ); + + // + has = isOBStarted && + isOBStartedBodyOut; + if (has) + { + // + analyseOBBox.from = + obStartedBar.NextAt(); + + // + has = IsExists(analyseOBBox); + if (!has) + { + // + AddRef( + analyseOBBox, + waitingBoxes // + ); + } + } + } + + // + analyseOBBox.Clean(); + ZeroMemory(analyseOB); + } + + // + // + // + + // + result = HasWaitingZones(); + + // + // Cleanup Resources ... + + // + obFVG.Clean(); + obBox.Clean(); + fvgBox.Clean(); + supplyBox.Clean(); + demandBox.Clean(); + + // + ZeroMemory(ob); + ZeroMemory(fvg); + ZeroMemory(supply); + ZeroMemory(demand); + + // + return result; + } + + // + int ValidateWaitingZones( + int barIndex = 0 // + ) + { + // + int result = 0; + + // + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex = 1; + } + + // + has = IsValid() && + HasWaitingZones(); + if (!has) + { + return result; + } + + // + int removeIDX[]; + result = CountWaitingZones(); + for (int i = 0; i < result; i++) + { + // + has = waitingZones[i].IsValidZone( + barIndex // + ); + if (!has) + { + // + Add( + i, + removeIDX // + ); + + // + AddRef( + waitingZones[i], + unavailableZones // + ); + } + } + + // + has = HasChild(removeIDX); + if (has) + { + // + CleanupArray( + removeIDX, + waitingZones // + ); + } + Clean(removeIDX); + + // + result = CountWaitingZones(); + + // + return result; + } + + // + int ValidateWaitingBoxes( + int barIndex = 0 // + ) + { + // + int result = 0; + + // + bool has = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex = 1; + } + + // + has = IsValid() && + HasWaitingBoxes(); + if (!has) + { + return result; + } + + // + int removeIDX[]; + result = CountWaitingBoxes(); + for (int i = 0; i < result; i++) + { + // + has = IsValidBox( + waitingBoxes[i], + barIndex, + period // + ); + if (!has) + { + // + Add( + i, + removeIDX // + ); + + // + AddRef( + waitingBoxes[i], + unavailableBoxes // + ); + } + } + + // + has = HasChild(removeIDX); + if (has) + { + // + CleanupArray( + removeIDX, + waitingBoxes // + ); + } + Clean(removeIDX); + + // + result = CountWaitingBoxes(); + + // + return result; + } + + // + bool IsZoneActivated( + int &zoneIDX, + int &fvgIDX, + ENUM_X_DIRECTION &dir, + ENUM_X121SMC_XWZ_PROVIDERS &signalProvider, + X121SMCStrategySignalProviderData &provider, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + fvgIDX = -1; + zoneIDX = -1; + dir = X_DIRECTION_NONE; + signalProvider = X121SMC_XWZ_PROVIDER_NONE; + + // + // Normalize Bar Index ... + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex == 0) + { + barIndex = 1; + } + + // + // Validate ... + result = IsValid() && + HasWaitingZones(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + + // + return result; + } + + // + double peak = provider.decisionXConditions.peaksBuffer[1]; + double vale = provider.decisionXConditions.valesBuffer[1]; + + // + double analysePeak = provider.analyseXConditions.peaksBuffer[1]; + double analyseVale = provider.analyseXConditions.valesBuffer[1]; + + // + double consolidationPeak = provider.consolidationXConditions.peaksBuffer[1]; + double consolidationVale = provider.consolidationXConditions.valesBuffer[1]; + + // + double visionPeak = provider.visionXConditions.peaksBuffer[1]; + double visionVale = provider.visionXConditions.valesBuffer[1]; + + // + bool isPeaksSame = + peak == analysePeak && + analysePeak == consolidationPeak; + + // + bool isValesSame = + vale == analyseVale && + analyseVale == consolidationVale; + + // + // + // + + // + bool isDecisionScoreBullish = + provider.decisionBullishScore > provider.decisionBearishScore; + + // + bool isDecisionScoreBearish = + provider.decisionBearishScore > provider.decisionBullishScore; + + // + bool isAnalyseScoreBullish = + provider.analyseBullishScore > provider.analyseBearishScore; + + // + bool isAnalyseScoreBearish = + provider.analyseBearishScore > provider.analyseBullishScore; + + // + bool isConsolidationScoreBullish = + provider.consolidationBullishScore > provider.consolidationBearishScore; + + // + bool isConsolidationScoreBearish = + provider.consolidationBearishScore > provider.consolidationBullishScore; + + // + bool isVisionScoreBullish = + provider.visionBullishScore > provider.visionBearishScore; + + // + bool isVisionScoreBearish = + provider.visionBearishScore > provider.visionBullishScore; + + // + int count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XOBFVG iOBFVG = waitingZones[i]; + + // + ENUM_X_DIRECTION iDir = iOBFVG.GetDirection(); + bool isBullish = iOBFVG.IsBullish(); + + // + int fvgsCount = iOBFVG.CountFVGs(); + bool has = IsValidSize(fvgsCount); + if (has) + { + // + for (int j = 0; j < fvgsCount; j++) + { + // + XCFVG *jFVG = iOBFVG.fvgs[j]; + + // + XBoxZone iBox; + has = ToBox( + iBox, + jFVG // + ); + if (has) + { + // + double iRange = iBox.lower + ((iBox.upper - iBox.lower) / 2); + + // + // Activate Zone Using PV ... + bool isPVPassed = + isBullish + ? vale <= iBox.upper && + vale >= iBox.lower + : peak <= iBox.upper && + peak >= iBox.lower; + bool isPV50Passed = + isBullish + ? vale < iBox.upper && + vale <= iRange && + vale > iBox.lower + : peak < iBox.upper && + peak >= iRange && + peak > iBox.lower; + + // + // Activate Zone using Rejection ... + bool isRejected = + isBullish + ? bar.low <= iBox.upper && + bar.GetDown() > iBox.upper + : bar.high >= iBox.lower && + bar.GetUp() < iBox.lower; + + // + // Combine Result ... + // result = isPVPassed; + // || isPVPassed + // || isPV50Passed + // || isRejected; + + // + result = isPVPassed; + + if (result) + { + // + fvgIDX = j; + iBox.Clean(); + zoneIDX = i; + + // + break; + } + } + + // + if (result) + { + // + iBox.Clean(); + ZeroMemory(jFVG); + + // + break; + } + + // + iBox.Clean(); + } + } + + // + if (result) + { + // + iOBFVG.Clean(); + break; + } + + // + iOBFVG.Clean(); + } + + // + result = + IsValidIndex(fvgIDX) && + IsValidIndex(zoneIDX); + + // + bar.Clean(); + + // + if (result) + { + bar.Clean(); + } + + // + return result; + } + + // + bool IsBoxActivated( + XBoxZone &box, + ENUM_X_DIRECTION &dir, + ENUM_X121SMC_XWZ_PROVIDERS &signalProviderl, + X121SMCStrategySignalProviderData &provider, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + box.Clean(); + dir = X_DIRECTION_NONE; + signalProviderl = X121SMC_XWZ_PROVIDER_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + result = IsValid() && + HasWaitingBoxes(); + if (!result) + { + return result; + } + + // + XOHCL bar; + XOHCL cBar; + XOHCL pBar; + result = bar.Init( + symbol, + period, + barIndex // + ); + result = + result && + bar.GetPreviousBar(cBar); + result = + result && + cBar.GetPreviousBar(pBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + // Retrieve Some Required Data ... + + // + double peakZ = provider.decisionXConditions.peaksBuffer[0]; + double valeZ = provider.decisionXConditions.valesBuffer[0]; + double peak = provider.decisionXConditions.peaksBuffer[1]; + double vale = provider.decisionXConditions.valesBuffer[1]; + + // + double analysePeak = provider.analyseXConditions.peaksBuffer[1]; + double analyseVale = provider.analyseXConditions.valesBuffer[1]; + + // + double consolidationPeak = provider.consolidationXConditions.peaksBuffer[1]; + double consolidationVale = provider.consolidationXConditions.valesBuffer[1]; + + // + double visionPeak = provider.visionXConditions.peaksBuffer[1]; + double visionVale = provider.visionXConditions.valesBuffer[1]; + + // + bool isPeaksSame = + peak == analysePeak && + analysePeak == consolidationPeak; + + // + bool isValesSame = + vale == analyseVale && + analyseVale == consolidationVale; + + // + // Calculate Scores Conditions ... + + // + bool isDecisionScoreBullish = + provider.decisionBullishScore > provider.decisionBearishScore; + + // + bool isDecisionScoreBearish = + provider.decisionBearishScore > provider.decisionBullishScore; + + // + bool isAnalyseScoreBullish = + provider.analyseBullishScore > provider.analyseBearishScore; + + // + bool isAnalyseScoreBearish = + provider.analyseBearishScore > provider.analyseBullishScore; + + // + bool isConsolidationScoreBullish = + provider.consolidationBullishScore > provider.consolidationBearishScore; + + // + bool isConsolidationScoreBearish = + provider.consolidationBearishScore > provider.consolidationBullishScore; + + // + bool isVisionScoreBullish = + provider.visionBullishScore > provider.visionBearishScore; + + // + bool isVisionScoreBearish = + provider.visionBearishScore > provider.visionBullishScore; + + // + bool isScoreBullish = + isVisionScoreBullish && + isAnalyseScoreBullish && + isConsolidationScoreBullish; + + // + bool isScoreBearish = + isVisionScoreBearish && + isAnalyseScoreBearish && + isConsolidationScoreBearish; + + // + // Waiting Boxes ... + int count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = waitingBoxes[i]; + bool isBullish = iBox.IsBullish(); + + // + // Check Score ... + + // + bool isScorePassed = + isBullish + ? isScoreBullish + : isScoreBearish; + + // + // Check Bar Insides ... + + // + bool isPBarInside = + (pBar.high <= iBox.upper && + pBar.low >= iBox.lower) || + (isBullish + ? pBar.low < iBox.upper && + pBar.GetDown() < iBox.upper + : pBar.high > iBox.lower && + pBar.GetUp() > iBox.lower); + + // + bool isCBarInside = + (cBar.high <= iBox.upper && + cBar.low >= iBox.lower) || + (isBullish + ? cBar.low < iBox.upper && + cBar.GetDown() < iBox.upper + : cBar.high > iBox.lower && + cBar.GetUp() > iBox.lower); + + // + // Checking Rejection ... + + // + // Bullish ... + bool isBullishRejected = + isBullish && + cBar.low <= iBox.upper && + cBar.GetDown() > iBox.upper; + + // + // Bearish ... + bool isBearishRejected = + !isBullish && + cBar.high >= iBox.lower && + cBar.GetUp() < iBox.lower; + + // + // Check Breaktion ... + + // + // Bullish ... + bool isBullishBreaked = + isBullish && + cBar.high > iBox.upper && + cBar.GetUp() > iBox.upper && + cBar.low >= iBox.lower; + + // + // Bearish ... + bool isBearishBreaked = + !isBullish && + cBar.low < iBox.lower && + cBar.GetDown() < iBox.lower && + cBar.high <= iBox.upper; + + // + // Checking PV Pass ... + + // + bool isBullishPVPassed = + isBullish && + vale == valeZ && + vale > iBox.lower && + vale < iBox.upper; + + // + bool isBearishPVPassed = + !isBullish && + peak == peakZ && + peak > iBox.lower && + peak < iBox.upper; + + // + // Summarise ... + + // + // Rejection ... + bool isRejected = isBullishRejected || + isBearishRejected; + + // + // Breaktion ... + bool isBreaked = + isPBarInside && + (isBullishBreaked || + isBearishBreaked); + + // + bool isPVPassed = + (isBullishPVPassed || + isBearishPVPassed); + + // + // Trend Conditions ... + + // + bool isX3MABullish = + provider.decisionXConditions.isX3MaFastOverMid && + provider.decisionXConditions.x3maMidBuffer[1] > provider.decisionXConditions.x3maSlowBuffer[1]; + + // + bool isX3MABearish = + provider.decisionXConditions.isX3MaFastUnderMid && + provider.decisionXConditions.x3maMidBuffer[1] < provider.decisionXConditions.x3maSlowBuffer[1]; + + // + bool isVWapBullish = + provider.decisionXConditions.isVWapFastOverMid && + provider.decisionXConditions.vwapMidBuffer[1] > provider.decisionXConditions.vwapSlowBuffer[1]; + + // + bool isVWapBearish = + provider.decisionXConditions.isX3MaFastUnderMid && + provider.decisionXConditions.vwapMidBuffer[1] < provider.decisionXConditions.vwapSlowBuffer[1]; + + // + bool isTrendBullish = + isX3MABullish && + isVWapBullish; + + // + bool isTrendBearish = + isX3MABearish && + isVWapBearish; + + // + bool isTrendPassed = + isBullish + ? isTrendBullish + : isTrendBearish; + + // + // Summarize Conditions ... + + // + result = + // + // isBreaked || + // isRejected || + isPVPassed && + isRejected && + isTrendPassed && + isScorePassed + // + ; + + // + if (result) + { + // + box = iBox; + dir = iBox.dir; + signalProviderl = X121SMC_XWZ_PROVIDER_ACTIVATED_BOX; + + // + iBox.Clean(); + break; + } + + // + iBox.Clean(); + + // + } + + // + // MA Trends ... + if (!result) + { + // + result = provider.analyseState.HasOrderBlocks(); + if (result) + { + // + // + // Trend Conditions ... + + // + bool isX3MABullish = + provider.decisionXConditions.isX3MaFastCrossedOverMid; + + // + bool isX3MABearish = + provider.decisionXConditions.isX3MaFastCrossedUnderMid; + + // + bool isVWapBullish = + provider.decisionXConditions.isVWapFastCrossedOverMid; + + // + bool isVWapBearish = + provider.decisionXConditions.isVWapFastCrossedUnderMid; + + // + // + // + + // + bool isTrendBullish = + (isX3MABullish || + isVWapBullish) && + provider.decisionXConditions.isNewPeakOverLast; + + // + bool isTrendBearish = + (isX3MABearish || + isVWapBearish) && + provider.decisionXConditions.isNewValeUnderLast; + + // + result = isTrendBullish || + isTrendBearish; + if (result) + { + // + // Select Signal Box ... + + // + bool isScorePassed = + isTrendBullish + ? isScoreBullish + : isScoreBearish; + + // + XBoxZone tmpBoxes[]; + ToBox( + provider.analyseState.orderBlocks, + tmpBoxes // + ); + Copy( + waitingBoxes, + tmpBoxes, + false // + ); + int idx = -1; + // bool has = false; + while (HasChild(tmpBoxes)) + { + // + if (isTrendBullish) + { + idx = GetHighest(tmpBoxes); + } + else + { + idx = GetLowest(tmpBoxes); + } + + // + result = IsValidIndex(idx); + if (!result) + { + break; + } + + // + XBoxZone iBox = tmpBoxes[idx]; + + // + ArrayRemove( + tmpBoxes, + idx, + 1 // + ); + + // + int insideIDX = -1; + bool hasInsideBox = HasInsideBox( + insideIDX, + iBox, + tmpBoxes // + ); + if (hasInsideBox) + { + // + hasInsideBox = + isTrendBullish + ? iBox.lower < tmpBoxes[insideIDX].lower + : iBox.upper > tmpBoxes[insideIDX].upper; + } + + // + bool isBullishPlacePassed = + // !hasInsideBox && + isTrendBullish && + iBox.IsBullish() && + bar.low >= iBox.upper && + cBar.low >= iBox.upper && + provider.decisionXConditions.x3maMin >= iBox.lower && + provider.decisionXConditions.vwapMin >= iBox.lower; + + // + bool isBearishPlacePassed = + // !hasInsideBox && + isTrendBearish && + iBox.IsBearish() && + bar.high <= iBox.lower && + cBar.high <= iBox.lower && + provider.decisionXConditions.x3maMax <= iBox.upper && + provider.decisionXConditions.vwapMax <= iBox.upper; + + // + result = isScorePassed && + (isBullishPlacePassed || + isBearishPlacePassed); + if (result) + { + // + box = iBox; + iBox.Clean(); + dir = + isTrendBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + signalProviderl = X121SMC_XWZ_PROVIDER_ACTIVATED_MA; + break; + } + + // + } + Clean(tmpBoxes); + } + } + } + + // + // Supply and Demand ... + if (false && !result) + { + // + int idx = -1; + bool has = false; + XBoxZone tmpBoxes[]; + + // + // Detecting Youngest Zones ... + + // + XBoxZone bullishBox; + bool hasBullishBox = false; + if (!hasBullishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bullishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bullishOrderBlocks[idx]; + + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = ob.IsStarted( + ob.GetDirection(), + startedBar, + isBodyOut // + ); + has = isStarted && + isBodyOut; + if (has) + { + // + hasBullishBox = ToBox( + bullishBox, + ob // + ); + } + } + + // + if (!hasBullishBox) + { + bullishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + XBoxZone bearishBox; + bool hasBearishBox = false; + if (!hasBearishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bearishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bearishOrderBlocks[idx]; + + // + XOHCL startedBar; + bool isBodyOut = false; + bool isStarted = ob.IsStarted( + ob.GetDirection(), + startedBar, + isBodyOut // + ); + has = isStarted && + isBodyOut; + if (has) + { + // + hasBearishBox = ToBox( + bearishBox, + ob // + ); + } + } + + // + if (!hasBearishBox) + { + bearishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + XBoxZone bullishCZBox; + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + hasBullishConsolidationZone = provider.decisionState.HasBullishConsolidationZones(); + if (hasBullishConsolidationZone) + { + // + idx = GetYoungest(provider.decisionState.bullishConsolidationZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + // + bullishConsolidationZone = provider.decisionState.bullishConsolidationZones[idx]; + if (hasBullishConsolidationZone) + { + // + hasBullishConsolidationZone = ToBox( + bullishCZBox, + bullishConsolidationZone // + ); + } + } + } + + // + XBoxZone bearishCZBox; + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + hasBearishConsolidationZone = provider.decisionState.HasBearishConsolidationZones(); + if (hasBearishConsolidationZone) + { + // + idx = GetYoungest(provider.decisionState.bearishConsolidationZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + // + bearishConsolidationZone = provider.decisionState.bearishConsolidationZones[idx]; + if (hasBearishConsolidationZone) + { + // + hasBearishConsolidationZone = ToBox( + bearishCZBox, + bearishConsolidationZone // + ); + } + } + } + + // + // + // + + // + // Supply Zone ... + has = provider.visionState.HasSupplyZones(); + if (has) + { + // + ToBox( + provider.visionState.supplyZones, + tmpBoxes // + ); + + // + while (HasChild(tmpBoxes)) + { + // + idx = GetYoungest(tmpBoxes); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XBoxZone iBox = tmpBoxes[idx]; + ArrayRemove( + tmpBoxes, + idx, + 1 // + ); + + // + // Price Must Be Inside a Zonne More Than 5 Bar ... + bool isPriceInside = + // + bar.high < iBox.upper && + bar.low > iBox.lower && + // + cBar.high < iBox.upper && + cBar.low > iBox.lower && + // + pBar.high < iBox.upper && + pBar.low > iBox.lower + // + ; + + // + bool isBearishBoxPassed = + hasBearishBox && + IsBoxInside( + bearishBox, + iBox // + ); + + // + bool isBearishCZBoxPassed = + hasBearishConsolidationZone && + IsBoxInside( + bearishCZBox, + iBox // + ); + + // + result = isPriceInside && + (isBearishBoxPassed || + isBearishCZBoxPassed); + if (result) + { + // + if (isBearishBoxPassed) + { + box = bearishBox; + } + else + { + box = bearishCZBox; + } + + // + iBox.to = TimeCurrent(); + XCBoxObject *iObj; + provider.visionCycleHelper.mPOIDrawer.DrawBox( + iBox, + iObj // + ); + + // + dir = X_DIRECTION_BEARISH; + signalProviderl = X121SMC_XWZ_PROVIDER_ACTIVATED_AREA; + + // + iBox.Clean(); + + // + break; + } + + // + iBox.Clean(); + } + + // + Clean(tmpBoxes); + } + + // + // Demand Zone ... + has = provider.visionState.HasDemandZones(); + if (!result && has) + { + // + ToBox( + provider.visionState.demandZones, + tmpBoxes // + ); + + // + while (HasChild(tmpBoxes)) + { + // + idx = GetYoungest(tmpBoxes); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XBoxZone iBox = tmpBoxes[idx]; + ArrayRemove( + tmpBoxes, + idx, + 1 // + ); + + // + // Price Must Be Inside a Zonne More Than 5 Bar ... + bool isPriceInside = + // + bar.high < iBox.upper && + bar.low > iBox.lower && + // + cBar.high < iBox.upper && + cBar.low > iBox.lower && + // + pBar.high < iBox.upper && + pBar.low > iBox.lower + // + ; + + // + bool isBullishBoxPassed = + hasBullishBox && + IsBoxInside( + bullishBox, + iBox // + ); + + // + bool isBullishCZBoxPassed = + hasBullishConsolidationZone && + IsBoxInside( + bullishCZBox, + iBox // + ); + + // + result = isPriceInside && + (isBullishBoxPassed || + isBullishCZBoxPassed); + if (result) + { + // + if (isBullishBoxPassed) + { + box = bullishBox; + } + else + { + box = bullishCZBox; + } + + // + iBox.to = TimeCurrent(); + XCBoxObject *iObj; + provider.visionCycleHelper.mPOIDrawer.DrawBox( + iBox, + iObj // + ); + + // + dir = X_DIRECTION_BULLISH; + signalProviderl = X121SMC_XWZ_PROVIDER_ACTIVATED_AREA; + + // + iBox.Clean(); + + // + break; + } + + // + iBox.Clean(); + } + + // + Clean(tmpBoxes); + } + + // + Clean(tmpBoxes); + + // + bullishBox.Clean(); + bearishBox.Clean(); + bullishCZBox.Clean(); + bearishCZBox.Clean(); + bullishConsolidationZone.Clean(); + bearishConsolidationZone.Clean(); + + // + } + + // + bar.Clean(); + cBar.Clean(); + pBar.Clean(); + + // + return result; + } + + // + bool IsExists(XOBFVG &zone) + { + // + bool result = false; + + // + // Check Validation ... + result = zone.IsValid() && + (HasWaitingZones() || + HasUnavailableZones()); + if (!result) + { + return result; + } + + // + int idx = -1; + + // + // Check Index in Waiting Zones ... + idx = FindIndex( + zone, + waitingZones // + ); + result = IsValidIndex(idx); + if (result) + { + return result; + } + + // + // Check Index in Unavailable Zones ... + idx = FindIndex( + zone, + unavailableZones // + ); + result = IsValidIndex(idx); + if (result) + { + return result; + } + + // + return result; + } + + // + bool IsExists(XBoxZone &box) + { + // + bool result = false; + + // + // Check Validation ... + result = box.IsValid() && + (HasWaitingBoxes() || + HasUnavailableBoxes()); + if (!result) + { + return result; + } + + // + int idx = -1; + + // + // Check Index in Waiting Zones ... + idx = FindIndex( + box, + waitingBoxes // + ); + result = IsValidIndex(idx); + if (result) + { + return result; + } + + // + // Check Index in Unavailable Zones ... + idx = FindIndex( + box, + unavailableBoxes // + ); + result = IsValidIndex(idx); + if (result) + { + return result; + } + + // + return result; + } + + // + bool IsDestroyed( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + XOHCL cBar; + result = bar.GetPreviousBar(cBar); + if (!result) + { + // + bar.Clean(); + cBar.Clean(); + + // + return result; + } + + // + bool isSupplyZoneBreaked = + // + bar.low > supplyZone.Upper() && + cBar.low > supplyZone.Upper() + // + ; + + // + bool isDemandZoneBreaked = + // + bar.high < demandZone.Lower() && + cBar.high < demandZone.Lower() + // + ; + + // + bar.Clean(); + cBar.Clean(); + + // + result = isSupplyZoneBreaked || + isDemandZoneBreaked; + + // + return result; + } + + // + bool DetectPriority( + ENUM_X121SMC_XWZ_PRIORITY &priority, + ENUM_X_DIRECTION forDir, + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + priority = X121SMC_XWZ_PRIORITY_NONE; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + + // + XOHCL bar; + result = bar.Init( + symbol, + forPeriod, + barIndex // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + if (bar.high < supplyZone.Upper() && + bar.low > supplyZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_NONE + : X121SMC_XWZ_PRIORITY_STRONG_HIGH; + } + else if (bar.high < supplyZone.Lower() && + bar.low > quarter1) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_WEAK + : X121SMC_XWZ_PRIORITY_HIGH; + } + else if (bar.high < quarter1 && + bar.low > quarter2) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_LOW + : X121SMC_XWZ_PRIORITY_REGULAR; + } + else if (bar.high < quarter2 && + bar.low > quarter3) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_REGULAR + : X121SMC_XWZ_PRIORITY_LOW; + } + else if (bar.high < quarter3 && + bar.low > demandZone.Upper()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_HIGH + : X121SMC_XWZ_PRIORITY_WEAK; + } + else if (bar.high < demandZone.Upper() && + bar.low > demandZone.Lower()) + { + // + priority = + isBullish + ? X121SMC_XWZ_PRIORITY_STRONG_HIGH + : X121SMC_XWZ_PRIORITY_NONE; + } + + // + result = priority != X121SMC_XWZ_PRIORITY_NONE && + priority != X121SMC_XWZ_PRIORITY_WEAK; + + // + bar.Clean(); + + // + return result; + } + + // + bool DetectOveralDirection( + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = IsValid() && + HasSupplyZone() && + HasDemandZone(); + if (!result) + { + return result; + } + + // + XBoxZone demBox; + XBoxZone supBox; + result = ToBox( + demBox, + demandZone // + ); + if (!result) + { + // + supBox.Clean(); + demBox.Clean(); + + // + return result; + } + result = ToBox( + supBox, + supplyZone // + ); + if (!result) + { + // + supBox.Clean(); + demBox.Clean(); + + // + return result; + } + + // + XOHCL supPriceOutBar; + XOHCL demPriceOutBar; + result = DetectBoxNearestPriceOut( + supBox, + supPriceOutBar, + period // + ); + if (!result) + { + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + result = DetectBoxNearestPriceOut( + demBox, + demPriceOutBar, + period // + ); + if (!result) + { + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + + // + // Specified Direction ... + dir = + (supPriceOutBar.IsValid() && + demPriceOutBar.IsValid()) + ? supPriceOutBar.time > demPriceOutBar.time + ? X_DIRECTION_BEARISH + : demPriceOutBar.time > supPriceOutBar.time + ? X_DIRECTION_BULLISH + : X_DIRECTION_NONE + : X_DIRECTION_NONE; + + // + result = HasDirection(dir); + + // + // Clean Up Resources ... + + // + demBox.Clean(); + supBox.Clean(); + supPriceOutBar.Clean(); + demPriceOutBar.Clean(); + + // + return result; + } + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + + // + has = HasSupplyZone(); + if (has) + { + supplyZone.To(value); + } + + // + has = HasDemandZone(); + if (has) + { + demandZone.To(value); + } + + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + waitingZones[i].UpdateTo(value); + } + } + + // + has = HasWaitingBoxes(); + if (has) + { + // + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + waitingBoxes[i].to = value; + } + } + + // + } + + // + void Draw( + XCPOIDrawer *drawer, + bool drawSupplyZone = false, + bool drawDemandZone = false, + bool drawWaitingZones = false) + { + // + if (drawer == NULL) + { + return; + } + + // + int count = 0; + bool has = false; + bool isCreated = false; + + // + ulong chartID = drawer.ChartIdentification(); + int subWindow = drawer.SubWindowIdentification(); + color bullishColor = drawer.BarBullishColor(); + color bearishColor = drawer.BarBearishColor(); + + // + // Supply Zone ... + if (drawSupplyZone) + { + // + has = HasSupplyZone(); + if (has) + { + // + XCSupplyZoneObject *iObj; + isCreated = drawer.CreateSupplyZone( + supplyZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // Demand Zone ... + if (drawDemandZone) + { + // + has = HasDemandZone(); + if (has) + { + // + XCDemandZoneObject *iObj; + isCreated = drawer.CreateDemandZone( + demandZone, + iObj // + ); + + // + if (isCreated) + { + mWorkingZoneObjects.Add(iObj); + } + } + } + + // + // + // + + // + // Quarters ... + has = IsValid(); + if (has) + { + // + double zoneUpper = supplyZone.Upper(); + double upper = supplyZone.Lower(); + + // + double lower = demandZone.Upper(); + double zoneLower = demandZone.Lower(); + + // + string prefix = "X121WZone_" + symbol + "_" + ToString(period); + + // + // Zone Upper ... + CChartObjectHLine *zoneUpperLine; + zoneUpperLine = new CChartObjectHLine(); + isCreated = zoneUpperLine.Create( + chartID, + prefix + "_ZoneTop", + subWindow, + zoneUpper // + ); + if (isCreated) + { + // + zoneUpperLine.Color(clrRed); + + // + mWorkingZoneObjects.Add(zoneUpperLine); + } + + // + // Zone Lower ... + CChartObjectHLine *zoneLowerLine; + zoneLowerLine = new CChartObjectHLine(); + isCreated = zoneLowerLine.Create( + chartID, + prefix + "_ZoneDown", + subWindow, + zoneLower // + ); + if (isCreated) + { + // + zoneLowerLine.Color(clrRed); + + // + mWorkingZoneObjects.Add(zoneLowerLine); + } + + // + // Upper ... + CChartObjectHLine *upperLine; + upperLine = new CChartObjectHLine(); + isCreated = upperLine.Create( + chartID, + prefix + "_Upper", + subWindow, + upper // + ); + if (isCreated) + { + // + upperLine.Color(clrLime); + + // + mWorkingZoneObjects.Add(upperLine); + } + + // + // Lower ... + CChartObjectHLine *lowerLine; + lowerLine = new CChartObjectHLine(); + isCreated = lowerLine.Create( + chartID, + prefix + "_Lower", + subWindow, + lower // + ); + if (isCreated) + { + // + lowerLine.Color(clrLime); + + // + mWorkingZoneObjects.Add(lowerLine); + } + + // + // Quarters ... + + // + // Quarter 1 ... + CChartObjectHLine *q1Line; + q1Line = new CChartObjectHLine(); + isCreated = q1Line.Create( + chartID, + prefix + "_Q1", + subWindow, + quarter1 // + ); + if (isCreated) + { + // + q1Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q1Line); + } + + // + // Quarter 2 ... + CChartObjectHLine *q2Line; + q2Line = new CChartObjectHLine(); + isCreated = q2Line.Create( + chartID, + prefix + "_Q2", + subWindow, + quarter2 // + ); + if (isCreated) + { + // + q2Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q2Line); + } + + // + // Quarter 3 ... + CChartObjectHLine *q3Line; + q3Line = new CChartObjectHLine(); + isCreated = q3Line.Create( + chartID, + prefix + "_Q3", + subWindow, + quarter3 // + ); + if (isCreated) + { + // + q3Line.Color(clrYellow); + + // + mWorkingZoneObjects.Add(q3Line); + } + } + + // + // Waiting Zones ... + if (drawWaitingZones) + { + // + has = HasWaitingZones(); + if (has) + { + // + count = CountWaitingZones(); + for (int i = 0; i < count; i++) + { + // + XCBaseObject *iObjects[]; + int iObjectsCount = drawer.DrawOBFVG( + waitingZones[i], + iObjects, + true, // Draw Order Block ... + true, // Draw Fair Value Gaps ... + true, // Draw All Fair Value Gaps ... + // + true, // Draw OB StartedBar ... + true, // Draw OB ActivatedBar ... + true, // Draw OB BreakedBar ... + true, // Draw OB WorkedBar ... + // + true, // Draw FVG StartedBar ... + true, // Draw FVG ActivatedBar ... + true, // Draw FVG BreakedBar ... + true // Draw FVG WorkedBar ... + // + ); + has = IsValidSize(iObjectsCount); + if (has) + { + // + for (int j = 0; j < iObjectsCount; j++) + { + mDrawnObjects.Add(iObjects[j]); + } + } + + // + // if (drawWaitingZonesBoxArea) + // { + // // + // XBoxZone iBox; + // has = waitingZones[i].ToZone( + // iBox // + // ); + // if (has) + // { + // // + // XCBoxObject *iBoxObj; + // has = drawer.DrawBox( + // iBox, + // iBoxObj // + // ); + // if (has) + // { + // mDrawnObjects.Add(iBoxObj); + // } + // } + + // // + // iBox.Clean(); + // } + } + } + + // + has = HasWaitingBoxes(); + if (has) + { + // + count = CountWaitingBoxes(); + for (int i = 0; i < count; i++) + { + // + XCBoxObject *iBoxObj; + has = drawer.DrawBox( + waitingBoxes[i], + iBoxObj // + ); + if (has) + { + mDrawnObjects.Add(iBoxObj); + } + + // + ZeroMemory(iBoxObj); + } + } + } + + // + } + + // + // + // + + // + bool HasSupplyZone() + { + return supplyZone != NULL && + supplyZone.IsValid(); + } + + // + bool HasDemandZone() + { + return demandZone != NULL && + demandZone.IsValid(); + } + + // + bool HasWaitingZones() + { + return HasChild(waitingZones); + } + + // + int CountWaitingZones() + { + return ArraySize(waitingZones); + } + + // + bool HasUnavailableZones() + { + return HasChild(unavailableZones); + } + + // + int CounUnavailableZones() + { + return ArraySize(unavailableZones); + } + + // + bool HasWaitingBoxes() + { + return HasChild(waitingBoxes); + } + + // + int CountWaitingBoxes() + { + return ArraySize(waitingBoxes); + } + + // + bool HasUnavailableBoxes() + { + return HasChild(unavailableBoxes); + } + + // + int CountUnavailableBoxes() + { + return ArraySize(unavailableBoxes); + } + + // +}; + +// +struct X121SMCStrategyXWZSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double reward; + double amountPercent; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + double sls[]; + double targets[]; + + // + XBoxZone signalBox; + + // + ENUM_X121SMC_XWZ_PRIORITY priority; + ENUM_X121SMC_XWZ_PROVIDERS provider; + + // + // Constructor ... + X121SMCStrategyXWZSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + + // + ZeroMemory(this); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + reward = 0; + amountPercent = 0; + + // + Clean(sls); + Clean(targets); + signalBox.Clean(); + + // + provider = X121SMC_XWZ_PROVIDER_NONE; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + } + + // +}; + +// +// Extension Functions ... + +// \ No newline at end of file diff --git a/BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.ex5 b/BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..6f01d4ac8f1fea3b87b677a40060f9a91c054a2b GIT binary patch literal 18960 zcmdS9Q*Z3T!%UKzODIfUnZ%y_NqvH=gZ2Y#8gUT3h|kH$icOgz>T1;Df8L4!8~~00Pk=MP z3Sa@S1h@hS0n7l#{}u~?_PU19>z|JQBC|8w&Hg6(BE5`-~> zGQ?&FW`Kc)GG62p0jz5_k$}KYCZX(&q7b+Gi>%+d<5c{DxcZH?gOXAH+7G6jA{TGk ze7VX!7CZb|nWK=yN?Fnqm0dYN-EA)KsCy=s4O37G4W$@Z8rx>$3ml=Vo=7qN7Tvc{ zYF=?0W>pI{y1`aY;e9c@(l|OW;AUWc(lcC{Wq}$fkDTD&i~MAd(`L2&{?v+U?i#Rw z06CCd=hhqV<96q+PZ&p_?UN>lRvCDI9x%=u|5S*oBYxISMVS)Vf_PQmWugUN(|(5q z*u(!hW^@Mgsy16%T%YFI>j~~TGYw6+PJL}4$A900Hfev55#OywFx7rpoy*Bx6@Mj zRI?)~?^w)f6r2c8WU~z=2JVmlj`J^vxQmx_o8mO46?Ll}{x%8AolcX&a~kl6nzc7ZqkcU%*sgOciXu5ATek=88fcZA&W%4gOD-}|OuN6tlkx?<>(Z?~!7+b+m!P`=_K%NHc<7^~7Vb9#(g^xW6{ z1CQ&XivL{jsAlGf=lQi^Gu=zq!-sH|6+!AC9$?9H&Q5*_`8i98K(yE#jVd;qfAPmY zIIhrPekB{%hUZ#|z_FuG&ze7>t(LAiTRky`vdO?@#)es(_!E$Ov4sEqQ0utVAy`p%~ zB9*xkbpw>ZvPHU-y{645l<_wqaZV|EUR93qA$3Z?oq&87AP24SRFV!|dnana-SK5Y zn>T0SnJ8`GvI%M^&YS#HYJid}pE6VDRSU&`E_17jDO1=;R2g{)Oi0)~YHz7}5k1j` zhi+9WDr z-LZgvH2e}6c2dAKhy3a`Cn0TANjlOmV2(u8h@uEF;E)P9WzqhS$d!plPf0C_@6Pr$ zK#S`XICq6(!=~`u&FDaNZbOgJLO3Ns3Y(h1t2~v~Gzq<_6u~UKC{$Qr73o%XLbPY? z%e+XWM$YQuklG3c7d~>llH!JbnHZgFkggDr``BzP=9arxtq~6DpT4<-dOzpN_R`N^ z-Sa-WOHmITBqBVEJT)7a<{tM96*X=TvBtB!t&+<^4^fOgP5ok+Y1v7aa#c}-R0}$n z&RF`564dXWYe@_C^`Y4o0SNKt+Z*XX{Anmti2;LtuTC9)Ju`_Yp2Gz9gvas#&52y)tyQXN){}1t0Sm`L zCM&&K>6))RW;(EOhj5Kox#uXQ=$lLota2A6eQ*b=FmoO$Cwro;`@}$v9vv_l502*KE=pqOiLQJdJvhW-}qNAfcFFLpQq*96P+fqD?PNl0|Y#@9RYuKy|Hjcev(>xf31SV8Q_6W6j{ z^byyVv(S;lAw%E2q@iYYFQ}52I zlq6hST!gzA8i5tB>uWnB`zxPSkn?q+!opx066XzhTtxx~z#=maY-B zJ@AWIn`of5fo2FkH3e70iqm03^tM%Q^JkLEtRzRWmR&&N?OM$1?ekFvi<@1`(lo6_ zf*Ti%dVW|MMMp|k{|!7vjc=yu^BIVUUQ&6`TkxG0qlra&fM1pqU4J3CeC;+zF*dwm z6i*I_QOX}NRnA3CEtL&*ng)&xL8^c@a~Bp8S@@nol*4I9u}R-Ku{sSuiT4+%lb_Hz z_c;@T5{b(J&=ZybU_>nxmC`(gP&RC+w`ivuAGZ#-jXI5yJ2{)uP|kh6-`dJ%!r3Cb zUf6S1pi>74N#S%RlvB92arJal)Gxt*J+KOV7=cSh8wrg-lz2`Ut$!MI?=5%gz24-6 z635=v(yy%)&ir$;Im5a;oEF#`-;)Sawt6Kk-I)ykmhCvKq71{TDZXXOIR6QM?h5ADY1A278d~|Q0GYO zo@QrsTv-i+`187(L{fc(XBW;t*gZu!k=0xmxab~Rz{C(8{aBGmCZ%OyhSTcl<{bUx zxKv7Sq|%L1j>EU*=3KcIlWbV-Y3_=Qm|noT%m1etxhfZSJa*grQ|j?*6AgO$%nhpZ6zNYL8%5S3;Kw%+$u(;A%h*xPW$UKYKKdHrXA>??GKHw0I=c}f9C zkbVub>@Zn-Q`$y$(Bb##Yf~K->ER=d(FT*eXFeuPgEOBb22J^3ww;Vhr7I92MvAP| zByW01ju{qCw`t?9e|i+$A(mDBkgVZk^0l9n$XFAB+o|rY;~} zj|KydBP`QtnErn9om(J72U?;>*k2~3b6Qy>3Q{8-4C~Z#e!YMBZ(k_(j z)-g?pmP0wROOuS+vCzW71m4*XPU&}*T;BQDXmBQd+1uMUp-^8weWo45Uw9|Q+K5<_ zRnkHc7dkr;I1HE5S$8)IAv)!wZ6B_mfH@kDAwN+XPfk^@Cfv#dktUdrP|dt(uQ8Pf zv$wuttYTR?d%h`R{BSP%;_~~#=7P~igDU~CS#I17IkOR-Ob137paT{rXxjHX=7Q^k z@Z3eZ+nK3R_K68Qn-uH(R-Du8mR-yv$6;N5loEjo_A-tmBa=Q#0?QM>Hns$FJSJYb zo9W4~8#TCfI8 zA2iT`NLYmUlnwa2fu?h*0IUzQZ*V=W-_Lz5^gW7R?u?9P+YRI*e4q|2A~py?JQDt_f^%$c^_Vj`~{X> zV?Gyqd{in#G^+6yzp;?uMloXj z?0%UMe9cLF(6@*+8XIt5-BMqjxpiAL;Lzj8)RcGy8ZtA`r9LduKhWy8rOT_)>Nk8X zKw9~;U2sS}ObBkj6x+6B6`LjTtV7By&?-pB;ze;W3f;cBmk2?wM==AqaMT-S<)<)X zivgs@$J7p}G^-@ToZZ%2PI$Z#+bbruZX`)utV&;?6qM7&gFyQx@knqG!kQw#;zuV~ z)&s_ht3M8{lufLPQ8scZbUIV){MCw#3aB9^X8I5-K zOEe;|i5Skz1d``i77#SfjZ9+k7$RdR5J-R`N@jPVdr*y?_iIOfQ%4}PsDC+tGQHz6 zJ-;HO@XLw!!S?4d`i|jpOrd*82= zqi3CW1MzC_ZB!h>vz8uHPw`PS4sYnMLywYs&%9P%I(|foG8w0}!PjMS*FoU1j!OQB zmJy*4b=whVQ7B80$rCi&od2+@quU_uBETVL17a$JY0SzX2XwvEoje4%%^*&&SSy12 zapGWWSEsrL{1kcZ$T^nA>%b zQDdu$ekJcs6+!b-K)cyokS+U(KnAg5wuj49;#pSy!)=?N1~t)p|J_didqis5{$A4) zoQoxhq}R=g+Bn=nK>BaMKpw*ZmLY9dDn$X7H@F^}%qm1mX`yRL_~urA`tWp`qp;Qd zgD`gW43UF$Y3v^(JPb0sA_cL}YI6wA7NPjwRUNR?Udtw4nJ+hMPImJYl%?Aqb1%GR zM#Za|oXkHC3(UI{nyJh|bUff0GV@D-44Q3A#^u1B92{A{u_W+zpHD43-5=a@0nam( zf$c*nO2brH-3lJGhh2hA)rLeL3XM+UA%;Hn&RPXH%DPad7^$Jv8Q`gtMz|jUzILO| zoLhtoJ6-FMakzhnBQKDBp{wklf-5TEa99SF&q;ach_^r<&9pip}IRgO_%7poI8^oxI7gIM}EOWZ0 zXISoo1q_h5^=iC-uPaIx=`S4teZLx*W4Ys!L!P$g0y%LXUHaY8+#Y*MDEGU(Z8&4Z$m67eE?c@VH*ld z#4EJBPjhdYN~1U$nbHN`Rj47xscJMhofV`c5E3dcqP|gLBV}EmIScPBd6*Q)kKOie z5%;t+5ew(byV5+(4#+NAA*v_C#NB95dvSta5ABo%EiT~8(Caa1jK$~-*UF7fe2E5m zd0UGc?IS8G7Q(xw*_huIN6?GU zj2@DE)4v6X3*NDS?aELa(x2YWCBcyzX%jGnA zxn^VlS9VLwjLf@|&tddia(xgua=f`Ibrt*G+T?T<;=ycTOuw+T_xXzinq?CkrUAZV7%eXrd_es==pFQwQIFFtlp~_wjk1@h{x{NxS9PA%q^-8PRywN*c~m!xT^! zAj)Uyf1QrUkZYY`x@_kKcPhvO>9-M->7HWFJTJFn)O0?}MA`#ro=K|?Bs`hJtVz$4 zsC5nAq#GT2zlnlJHKb5n@!Udo#3?zWuPJG-Chvs%Qm(N2To{uGc5Z)Vo7bZ!u4J2p ztFWQnbG>dzPkYmIleMMI5juY#f3;qPbutXQ>k6ne58U7Avc!;23#~Xjm!&j;3$#~{ zaW;kx2xlybXy49tA~75hz2$7)jNzuY)|WzTL3ny+imjF)$2bI`Tej`lUDw8*AfDad zpY?b!N+IeB#9OA<2;zDzQlTd_3o?D5DCTCr@_|8c-d(f-$9&c}bY;Z)nVrVYvaWdpRHb;lm_?Rfyj4bInu^$s%RclLj+gl_4~RW^KW( zo%&v&{!S)^(H2<8C!|g1W<$*W&V(snx`1o|!(OTKgTR%;2CSIM?}*e)n!z_p#FmK2 zbiw{4DNbQ^0ru)ZUql?I3VjH%iVp>)?=a`|DOHtRvAf^km)r7Zj?S&K$E}+N`d{U5 zi8R_&Ui&0tbWNLi|9-t&7KL+28wX3e9#-ef2OXQctyILwImw;`4s$3QSKzK%MaZb; z+ey~W6!w}Hu)DbBrL&6^d3aNj)eb~0pwLt8d)61x71x_Lh=!5ak28I78@M;^J%)8Ng;s4wf^*y6gP^wVyfP zIXkTqekvo;1Y}jFYS#4}&H}(;5wAh%nFy#GRU*wzqyQmBFE`FJlAZQNr>z9#%-d>0 z5^&j9pRB`hOv04+3mxn4tg0RTAd6N4sC};cJK~Ek0s}MBs`1|}`VvxC0W2$ST(*<} zH>coCadWAst+KSahkvjB+1TUwTO2CkkG(?#Q+eMRjsJ}?mMxJ9Cy5cHw6JnH4bF@C z%ML3s%o2@-B;{D1R_ivqd!o$~^yEYp%3&Yhe>|H*NwX<}2C#OhS)(o5+>cqGbz?5U z&Z>s7$Gd2TI%()^t&zH#gjqTvdUk{P2R|xxHAQqqitz^&ETY=AvI3%o6k3hvOCpsv zX@KZR*SSeI_%K5Xw8%(HRVh=F(O6k1w`b4w8z&4&(KE!I5|r*)cyD>e#X(QdH+XGr z=)~P4(mLz@2C&d&7dcT&dJA{GfJ-^Tlq)LPa(tnp;_iqV*fLixH=+rY_5DUej<|ke zQEK_LkN~K0==US(l=G3v{sa@_UH=DmVgy{s6*nx_3QGN zO~ilg^ya3e&wx>W$Bb@k@jhdM7pVT$Y20E%hiom@F6g{#M`uF*-$_(6$;;9!s+EqU z!iW^7SRD?d5Y3=QWA|~ks>pxy?T<@HCjSGU2yyb;nfqN{F$~4DPTrr$(O-BUAm^9T z7f__&I*!edA@urzvq~GBibb~^Gu)qQ!)=2NX~qI%-2;rhCS}!e zY^8-}W~XsCDT0~62y|hs5iGsfUOhrB;|dS|f4*ozU06d^=(PGgpQdcFBBK|!{IjQ( znRlwq^^Ip{d=&?-q{a__`#OBf>Q`~KPSR<&laNT;kF}4Ei?RB*0+OKOp;0o_yf`}5 zlGote?Rv@}b6lc{g0Qvw(>uhqK%hS(ccf_l0I~L-OQUj(sZa+-x7-o+c3wR0iC02Z zFU3RQ@!yfw7B{C)Y_ZTEJQl)TU2bbSiM8y-=Mw^XLlp@CeIglO#l-IeHrR|6vQNmM zX0Y9QQ8a|(4=-v?d@ePsmc zVp}2g)8Bet=j#sL8jGFS<#~%BLU-P51}*7q{>ucd-}Be$gt*JT5c3rBEvj$Zzjpd_CC`(n3l)X(xr>`_)v;(r$fJpYNBclBxRjVc?nlkB+Hm zF{Q|EBX;>`O?!#iEs{AyW@oG*Pj!P?EB;IpZDepi`mh)i?O1jjQ?Qmp4a2Baqv`7b z5Z&+T_;*9^q&o8(qLQ2)rf_$5`lUZ9hNaEWD1fO>Q~wGiI!;D#c8BQjv|HH_<9E4p zJVwdskh2D@r6ZJUHBp)-+|O-r|tKZ*l5`EaYFL zJRP6V?D{cb+S;>D8w!Hk5J{{GJut-2MM$^(gutWhSndu&g7>>}VDc6Co6%g{Djqft z9c~QvA3~8R+A0}Y%@^9gxqC)=xq5q(7ce383o6s7 zda|Pc>7I@lc2z&DG9Ye?qIZ0k4YkW zyI(upeMR~E@Bm7qIO7n0!NN513E^tz(q)J5s+>D6g=J90^l{k!ReO}7FLIiWXy}O9 zut=AvzaDJFA28rf;4sTzf;C$W)aq(_VOMbcY(7MNIun5t2rB2#&9NB%m^2v|1hol^ zRd)aVmmsEbu^u5d5ykY``7+LMiRCT#r8K)pgF+6CJ@#rIM1@I$MerKaWC`0Y|q}!m>}|z{clyzAJHQ?3u0S ziQYk3%=nkDL%yiWt(69od5ntw-L8TExiC(iQ;2fYT_T`p(e9fbaqR}?sRZFy9yb?4 zhF)Z9hz*)oh4;)D!P#K$!t&DsZFJCprmMNdphR{-=;+~F_M!^~VSOGTL%|q>&e2mfC`z}>NWy-_x zdR~Jwr+7027&>d$)e7-Pvf7&O#UcVW0*^UZ8;x`t@`{$f zh&R^B`{A7h>Y_JHPIdzqOC;fV+Ggwdf&@}8m7(1$ae2D8_B+j7+K7N(e+@Gkv4t|5 z;iZnHuSgWig*ji;ajV@J11<;;dR@@YkK#$ z4Yw?I7i725R1da*f{TD-)o`#6B$Ku=aFUhMSoCGy#FuE7Zoi3qFvMC?TUk{^hOVofMXcNBM$8qVoFw_V*=H1AS=@3*#8;r!;^B$)A zJb34)R!x*G{vcYDmE#|X7o&ZY#?x3-5vyl zv%Pkg8^O2+j4x8mq%tMybfv`8=X3--ouywZrTXX0P5I#OTqf_&pfOmVv*{P3K6dd_ zbSZh2AFS&B_z4Gp+5l_hv{sZzaBCEe=@ff-sd`S&8Q&96$ zGOZ(~>GCYW#EVq1sK%7J7wErILht=wMLWg>r=N9X&odim&JCWFmkH}cQPJ7EuyCrv zVgZVMV3ytflyH(9}b$UXtx=8{dJ2v3{RSLut67dOIZ`+5Xc{M-x-UjLSI% zKsGhCu2}udj!X}zJr0Y`=J}=>zR)qa+oSY<{U2@fb!VKT&WkXNm3@J=p?>tp(j%Q6lu{rtF%t2#{e zD!V2N(rhU$I8R3U@leX#q%WU`J3-r;40(>)*^n4r(YrR4xlOM`&V> zz&7rA$y$~~P&HEGnl*MUy7|=HoIO@zf8#|`La=uBODK}7l=Lob$_t+NHHs3vn^O4i zmuR2{_RsO}8Nn?_c0)MmwWGL`6cW;OOI~HnLUz3`Yo7VAC?~pJpk;&bO5ZHBrC`RcWSz@j}-hh~Lijr!YBVf9_TFy8Wv6>Qk zr?STtybAQN0tNlGr&cD0{sq{T;UIbHQjCSlgAu3c!5wgV(RZpj6v8`8F$*!pg9jhy zp#sZ(`-(}el8{VEcH$7b{>iEjOe`847h~}R+nB;w?*pMnm(k5_saj^+8?8*$>wRai zxouU-I(M%gE%1ds8j+rsQu`200Z@lVT$>#8KONG*BL5JEIJ`;(2|G+BhShrWmYj}h zPOr+*Z`i`+)p2@R_RaJf>uoNXR;RW_dZFTfA0@B`A}i9AlTA1y?^@ z%2H!8#0As-0y0=j3ci5ex-ewDscsM&4oFmbJk3z>n#pwY+4BH6mWc5KYUYf2$|@&q zdS<baTavXm{3Fvdi+((T3PGB9jq8A4tpw)Y&O&G zNs%2dRRS{!Cq(fA^~AAP!MoVUzDZiNF3nS~AIQk8@}^ET1K<>XaWuh}IHB}OZ&7@| z3a5t+0V)!6cwoD~_mfQ)vpQ1`&dp`l=X_GiVvByp6#e}hqRYi0{`E^zc!gGBU)N~H z#rV30Y|g5*GvbQ7NcVJI){xWrSm^a1v~Lqh{LoU@0UjOEzh-l!LVJMvkjjDexl>Kf-?jd5ioZ1hVf?@1^?dQ;d5swE=r{b)+^Z%Qn^9M0OkTv(wie1JNNoG-& zgg<)a7#m=d3!|>`!|uJu#@M#Zhe?G+@H4c6*wZX>O2V@_kpjYg7t+XiWJO%%7!7 zg#}dhp^J`lEG6;sR3{{}W8+BwUIi_!F1w55bQ#E8pU4vPG)e^b6(~z>$$=j&hdfC? zWMzO&l^3O7yIN7t6b14sn&W?n#*%r{x-AK&R2Yi2rOJ4;o2#Bc9{Wpt?V3{98e8~M zYXH>M0L9wR{`9iR*Li(!Jokflg;ll*tf`N(MMG%+g+=|QTw@|{;MTrAIgEY zvnPNRXfpo&;)eq=OuV0yam1lX{;CTd5-6bHOip;t3sZCH;_A0!*3{)Qm7tR7@jr>8 zRe2L1Rf2mx%;GN9cNLvx!tYG(83dWQ@zhRSY#BN!G9=V7f5M^ttR&3{?W(|HE@VD8 z(;*3GMJD*7x({Gn;>4bu!|m%H%`}k1bsqW^Q}$CZxOqomC>{7fboLjRYRBCc*egq> zoye^)fY_bKn2J$m6%)B3ElFSv1Njr_o#LmL`PB6xwh@royj_qNTE z(U=$iq;lZIaOWA=DCJ+(Gi3}tJ6B!Od-h)AITWm5N{wjqY^4m4^pt&jCJP`(&v*2Z zLV1kQ3h-Vi2LlQOWP2coUtbckg1z->U#PD57JUEK+dyODx>u)?C>C?hPxV$a#N;Jy zbE*uD+K5Ib+MOu<0h1{E0a{^fyWnngOb);vd_OiX&;pE-9qFgLQNgRw_{JuinL3NZ zU>k4>Itan9-t~~~8h-Tqr-z*UZPL(1w7f&neP|4vp1B^q#VKJgSg1_PJS60q>@zo! zkc*|Lo|su?p+aai6W)@TDx11JoBo`w4A!9ZQ~#OMcuSU6zzYZAFs_F+Qo7c6R(un| z&ETb*`ieH#1eE{bP>6UCzMNw?18w3J=)oX|3~+0GjT#V?3!vl6>&2iv_K5UbJG4cz zoVqC+H);e$x&vzMgZ0*1D*|$RA7+4fm7+Em;NUoG84UN5dn^Z8APQW+LK6#Oo~ zSeD|9jexxNJ_`6$gDA^J5eg7<%zvCU*J42)tP-hL^t~hgIDM2R(Ph!PH2tYhmAVi0wC{MSkv|AXJR}=oMzwCa7hpcaJFKnD68ux+#Xo^?$BZbeNLDfH}XjiwhU*w-lFR5M_(h3 zWE@(wYUXT+l&G)UdQ*duG4Hnzmzs_?`6_+{Waq8H3>ASc}To~28)n_?3Yq# zEvmJ&6RztpYl&{K10QOoY0swbNi8wMJm2ZQIs}*{2W}7L700C^VYaLrUg!&0sSr77 zDyR7xsP?%*W9t1=mR2yD#iC@pg%%Ggm+nl-1P@jU^egkC06^Cm&Tr+GWFbUf527%Wa9 zW}NUKump~K|KJ{P_aCj&I2Us2nOV&ML+DsLJ(_x5l}%Cmdj^dqKj5Ice}TwfY6sJo zQdc5E!*T{yhjV`bsLf%;C%ljtgq!Xw1fC0L1^^0e zV<(_ek36@1d>yK4mzcxQKL&cPMzp&X-3Q9A**>3mMSNmmi!%9nB?JD{&Q;5HmT9uq zE<$t*V}YY|EVf$OBq7oRbPE*K%8V{WGX{qo)DaiipXhZ@;AA=v!(c>WW&W)`f$$?! zpQp*P5euP}i-|!3aDStt>!w$~-uinAj3^d#LBba*H1d?d&MJ{GzTeGIMqCC zZ6%FL@ng-L#i-#cEa>|mS7*=_|C}%oTn>N5%NgY!{NY8SrTa2)DxeiOIp5XJQY0rK z+vGJ{WH#{+))x=sg6Cht!oT}MpoXEk#Mq0Bjj+~@8WH{+lCd@g@qm=10R=w$<)7PH zE*PnZ#xbRH?STaS#}M?mPNXu>&3kG{G-ONht1A}p+hl+|uW7b64LdCjpGHMKI<8TZ zgUufsOlBH!^mO8Hk`><881*=c$dK#EDc7_KcG1J7P0{8``y6077U24tWoqGin(Qe< z8p|Mxydw`2gZ@+1y8a%DbnL7I^t>YBJX*$xKr|d+I`^r73$I90)r*4JaQd$`y$v9q zn{5ti(>4|i)|axZZ&YK6rZA}}`z{r|M%DWw299VHM^>0gjS#paG>7TphK`_#88b|X z%D#(;I#Lgo>0EgKfgpuNHf)M9WiP{_JcN}B3dc9uxv$LdbgkI_@fF_xuJMk(vaZ>Z z?tox>$$~x}EgYk7IKikaEr}V><9v3<+;W%m3CGZWju|q^NyVKU%-e8gWbW6ekE|d3 zmqzI%$E`_R(ZfGBAM|^RoIj5XkoGO*M18OJ;dDw{df0=xytzM++t-GB%XZKGMVNPR z*7W5J9dP>>c3eu=7cx%2lq49m1qBI8Din^L)%q|ycy_8&vhQ{~H?B&Gu>lg<1N^T` zG*Y(LFc@2Zebt3;Q{W4~K-01re~U;(*GRVSl33f6u>j7oRVH7KerEyrm|772;-y{T z+1kvt*Ept;_i(#E7OF$1QdMb!3pmCMa4HfhJw&gRvy6TEN!jJu%>7d(Mi3QuQg|P& zH2Kg!QLmHrtjl}8`tmuGXO}wGQK)5LE0wX~q*fPDYPaoQnN7@b&~TYrrYphKQgj== zbpMB1HKbg}-!tWKaP0tGdK{gyJnM-3`oCKStNrIemLS~|fvL=vZzK8)tfIgidW zdCrZ)nzNT{Iw~uP)v%zQUALKNOE76~iz57=0e6h4`EM%vigouj+ogCHuFbXZEnG(+ z!a3%&zat9jkKkTt zupTuWM=Wi>SoIiC$dCBMFD%zEdkrmGu%WRc&tC4{hNQ4jK~2{?x_n|W$m^U3OyyUU zY_Q}5*z=Q0(@uj*Ct zQU;yb8cYIdLos`}=cf=<6LFNew>T3avvK|WYx^ZLh7k8v+3{vBpKJ~u85<>3gD8w9 zui+(u+hWAVHBjU_x^(KjF8H;xeVK<@6GxW3B6Kfhf4rCuk{#kM!G0xLuLb`=*2v=g zy2G$m{Hw_@;`3!$-O@_G_LeZ1tku&{)gpx}VwXqrAh&!)fG@$;bXDx)VI_h0Bz|`3XaS80O{IjimTsL z)3ZIOIV7Km#b?gF#{1;4 z>RdC%E2&~$*I@?rfBJ6sLP*{O=Sg7&QLC(=o6WCYX>kseE+h*1Z+eAW2gO%}q%loe z_t+KPmEQz!3b3@TJe6o7+PcQ3y3Q%Vqm#q){@%(c?uF$z9ccSX)R_Ez4iVcisg z^@yc=;OE)}c>LHSzknzWpc)6i-I>j?@kCWrC&)@0Y`lu;d`)U`fNSAHUP_#!mQ3Fo z^zDt?ip)*3G+34U)3f#MXD9$MjwBgGE&mHCAHtoRmc&Fg#OCSbCbl7NFSg;D62AY` zL@fJchQk*O6e!Pzrc_~a|FF^<#5`|6s1Y(+lb|+CbvQv_?-PL4Xf7PTv?MiK-@^}78}s-cyr{;#TfnY4Iw zhqwV}`Gu$;HY~wycSKOEuprbc)EumakqF1CJw(=@L(|yA&{IxscaEa>AMl+CxkGEU zHYTS|T%C%NCS`e3f8@NPSGK{a_Ymf2J>r1Le#Sck^Ts`KB|WRP%C(SL+k_L z1qw77VP$3_chXlHi3TN4qu8r;WOeT&ahYFF$s(OrS$GYg&vXkzLsR}Hs-XGSh#nIkKL$b!RV^KA z#u)ndrOeb_^~8dHxq@)@1-KDeoo^7}Lt7Dqhq|S%G$My*9e0c8-TjLu)XF7=zh3m#r)l5@PNokO zo}gCIP!!XaAuGHolbv>CY8;XB%5OW|H;eis=F0eb_UdWRPg z{Ckn{fKd|isogPuH4Ue0n6e{^XX=`oZ{>6u4OVr(d|)k^M9_{_Td``a$+H|Ic#k+{ zBnt*`o0CWDZ~esfMAXlC7U~1Ao$1k#r#M>Sh8)MMk&BR#+)(Wb;+H*I0j>O{PCW_t zMMc6-_-@HTcv177|7K)C-5Dok2YIurL+t>uQS@p9e?oB z)_l3W-(TUdhFJqiJR?%Jr#J-ym0<3VK8X#?QzI9m2)TEpz;HB@J*vdQkh1VGuWq~S z-dtrkE(<2=-ebz*x~Q)iDQ3ZeJIC>oL;5o%z3f}}XZJI?F4ab5YPsTdy_@V0&VSh+Pfniy#7=7oO7X{uz0Oz;y_c$trSGKM1paDyJNTEXZ}E6jIX?0QW* z5rD;d);>w^MYJpOI3tsiVe+%IIzSkhBHlViLr#4jpt>42tEa_7)QVl)x^X+9_Fd44 z4DwywG;+4vW|bq7`}ulm%d$AC(!7Ca4URb0fTcAhK9RB9#FZyz-7<|RRtGfBKYxHO zmHj}GM;l(eDAog%$PdU&Hy30j$1uW+o|+W04aYL&rf_^+j$)<8B`7kRbr!5+6#Ga;scrUvp_3 z)OKMAe%EW>c0FA(|5IvX8+pI{g0OOb?d&aiG7IbHIM`@WwGbwKe1bhJ#6Gw^+cC__ zO%22Qf(_1}G!SBkMw1wE!b>ZkEh4wAn(DP7NM!Rl(+CclF9~VW3FS^{md4iczUh{m zRsbV{g>V>8rKLojLj7f~r#6J-lB+c8KaCnR_HR*(b~4YoeU^_l zbowE({FhDn0o>}N@i{%5bvx79J4uBR8ohlCtQuGWO{%Oym9Cty=3SZTE{F<-v?0Tb z3~_PH@(v>3zmnI#%zA0ufTU8=<*Qv!r%&G0mH~MYx<09x`kMHf_LQ4y{!oT*DKmgU zy)}B|COPBt(I8G@5^d@|L9X9}5e%|{v@-`Ob#UK~#m>Wtpk$1+<^sQbP48L#4@uGA zl?@ihe;c@XY$yDr^uIDkR#7rw$f^=D6pSp z(47$!?eXfDaSgGZEk^ty@VkHtx2+Fe`%4nj@&|VFv@LX`C|GLAdl-$z_*xSgL@wT*CJ2GEp-qix+V6gZlsrnAF? zYBFn&-@(ByoIQ;1Hr35u*NuXHZ3`Ct=YNoUJ%RO>S~|$E=zc5PPpjVH3SDQ=7Cyz8iACBq}zTGf*J3LYcqC zN7svRA%a>OU;keK!3RG0rEW<}9$hKebGaL>*$U@<9KHSo)bIIQJUR-N>4IcTbQTU~ zX+4-8Qlc5PVrRPy{-r7jE&I5^)EjtX5cr6MqHuB2{uZ@ryS_GY1|KsL?SllZo8gNE zwUp|Q=8!K)^uqr9^HUbKUMk}5LTx`R{ZO^@Akr}C@wMdx ziFmXIzdI#f%zT(4vHw9<_y%%3!w@%Ui;-F&daBPBcOlI4MM*;m`t1H{@iu9FC6287 z!hCQJ6RCQ|am`*ZkRl8gxXV;3~N;T*Q=jS3UosI-Sn|)?ZLf0vvBeD}B!A`c; zEYW5$PPwi|+8iUQo((ou6jD+G zc?8WrZY*1&w<*tK%#jo^hXSyb zkZg8*1xA6FB`A!Q~`eEpn1V*AnYq)lFh7j>5ZqSc+fdB7NoAVpjDzV3@2x)XZF>Nd<&3e-O~xDJy1If>jPizZ zo%2XK&(H602ajiU{Gzb8Mr?V}+`v)A)DBwYm(ycnl*OKj5TlLMOBGh%r$@!*nRift z%rS_G6Eb97=kW3>ghJG@b9dexLS+xIyb-QyR452t(ZtoZS8PdUh(zj-i$OuLvo6f$ zXXE7DK6S70?0x+>2o$H0Cp2I#Pz5;`=78D%H6(*YAWEvRj8owUfg}c({qNA2F`XCt zvBdx5E@ecHxEP8%MBRvoL?{|GA0FK?sl!i&i5;uYi|$W_!E}J%CAPEa{H-|D81(k> zJ2GcAshVF>T!_R~o}`JE;N)YsobAsE=JfFk*lxaLHOew-p^QsrJA_0PlI*eJ+W)8!Eanh~UjHxws8|25=g%3k-j62+do?W8OMi zKjjRsuFOzbj}T%)E{b66j3>LB{qmOPH+2f!j|-tNs_tSK;??IEb|MwI7H@Ee1>4yS za}p66>VN6F>%xE8#JS*?kd`h(9E&gFh}xG_o|-(Wp=%;qM4GqtGiUxwpHLfxB9oZmr?N}h z7&))P7~Pnq=T48XZo=G@XQ$RiOYisc@aRPB$~BOb8p}aWX_m%P?QogIh3+^w#%<+# zTpJS#14NsmC%Bm%d<>L;(I~D!_V|?9J7C=rk3}E%d71+!K+F!%T8SCrU0>+77SXy6 zFYG@(X2u=3l#+h@P8>c1$j)DUTr6t^C?#c*^ZBWwVqE$;3jQwK{)?(VQdEZ?6q0mZ zo6Ennno(yACM)bf6bbos8aAY7S@Dq~kLi9sy#FJh?u$*zO;P1VIgo`SP2Ag|%3#4Z zASlwV1IK`GQugof?+EN&qUHd-+Sv8|Li(-^@~xr$6fvGRjU*BJ*VpdJxXaJ6aIzB% cXw0L5qMp!)G9_#S)WLl*3$bbeckC6H&y)I{ivR!s literal 0 HcmV?d00001 diff --git a/BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 new file mode 100644 index 0000000..eab17ad --- /dev/null +++ b/BKPS/14031218/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -0,0 +1,1064 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCX121SMCStrategy +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../Classes/x-121.smc.base.strategy.class.mq5" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" + +// +#include "../Signals/x-121.smc.xwz.signal.class.mq5" + +// +// Definitions ... + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCStrategy : public XCX121SMCBaseStrategy +{ + // + // Public ... + public: + // + // Props ... + bool useXWZSignal; + XCX121SMCXWZSignalDetector *mXWZSignalDetector; + X121SMCStrategySignalProviderData cycleProvider; + + // + // Constructor(s) ... + void XCX121SMCStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + : XCX121SMCBaseStrategy(_symbol, _period) + { + // + InitialHelpers(); + + // + mXWZSignalDetector = new XCX121SMCXWZSignalDetector( + _symbol, + _period // + ); + } + + // + // Deconstructur ... + void ~XCX121SMCStrategy() + { + Destroy(); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Max Allowed Required POI(s) to Find ... + * + * @return ( int ) + */ + int MaxAllowedRequiredPOIs() + { + return mMaxAllowedRequiredPOIs; + } + + /** + * Set Max Allowed Required POI(s) to Find ... + * + * @param value: number of Required POIs + */ + void MaxAllowedRequiredPOIs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedRequiredPOIs = value; + } + + // + // Overrides Actions ... + + /** + * Destroy All Class Implementations ... + */ + void Destroy() override + { + // + ZeroMemory(mDecisionCycleHelper); + ZeroMemory(mAnalyseCycleHelper); + ZeroMemory(mConsolidationCycleHelper); + ZeroMemory(mVisionCycleHelper); + + // + ZeroMemory(mXWZSignalDetector); + + // + cycleProvider.Destroy(); + } + + /** + * Check Conditions For Signal ... + */ + bool HasSignal( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) override + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + int pushers = 0; + + // + double sl = 0; + double tp = 0; + double risk = 0; + double entry = 0; + double reward = 0; + double r2r = R2R(); + string provider = ""; + double volume = Volume(); + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + + // + bool hasLong = false; + bool hasShort = false; + + // + double selectedSL = 0; + + // + // Start Calculations ... + + // + // Retrieve Common Data ... + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + // Required Value For SL/TP Calculations ... + double points = GetPoints(symbol); + double pip = GetPipPrice(symbol); + double pip2 = 2 * pip; + + // + conditions.time = cTime; + conditions.symbol = symbol; + conditions.period = period; + + // + // Check Spread for Signalling Conditions ... + // TODO: Uncomment this ... + // bool isSpreadPassed = IsSpreadPass(); + // result = isSpreadPassed; + // if (!result) + // { + // // + // conditions.Clean(); + // return result; + // } + + // + // Detect Signal Conditions ... + bool hasSignal = false; + + // + bool hasXWZSignal = false; + + // + // XSupDemOBS Signal ... + X121SMCStrategyXWZSignalConditions mXWZConditions; + if (useXWZSignal && !hasSignal) + { + // + hasXWZSignal = DetectXWZSignal( + conditions, + mXWZConditions // + ); + hasSignal = hasXWZSignal; + } + + // + result = hasSignal; + if (!result) + { + // + conditions.Clean(); + return result; + } + + // + // Combine all Signals Conditions ... + selectedSL = conditions.sl; + provider = conditions.provider; + + // + hasLong = + // + IsBullish(conditions.signalDir) + // + ; + + // + hasShort = + // + IsBearish(conditions.signalDir) + // + ; + + // + result = hasLong || + hasShort; + + // + // Rmove Signal Condition ... + if (result) + { + // + // TYPE ... + type = + hasLong + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + ENUM_X_POSITION_TYPES xType = + hasLong + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + entry = GetEntry( + conditions.symbol, + type // + ); + + // + double slAddition = 0; + sl = + hasLong + ? selectedSL - slAddition + : selectedSL + slAddition; + + // + // RISK Reward ... + risk = + hasLong + ? entry - sl + : sl - entry; + reward = risk * r2r; + tp = + hasLong + ? entry + reward + : entry - reward; + + // + signal.sl = sl; + signal.tp = tp; + signal.type = type; + signal.mode = mode; + signal.entry = entry; + signal.volume = volume; + signal.symbol = symbol; + signal.period = period; + signal.pushers = pushers; + signal.provider = provider; + signal.time = TimeCurrent(); + + // + Copy( + conditions.targets, + signal.targets // + ); + + // + result = PrepareSignal(signal); + + // + if (result) + { + // + if (useXWZSignal && + hasXWZSignal) + { + // + // Configuring Amount Percent and ETC ... + bool ignoreEAVolume = mXWZConditions.reward > 0 && + mXWZConditions.amountPercent > 0; + if (ignoreEAVolume) + { + // + double cReward = mXWZConditions.reward; + double cAmountPercent = mXWZConditions.amountPercent; + + // + double cRiskReward = risk * cReward; + double cTP = hasLong + ? entry + cRiskReward + : entry - cRiskReward; + + // + double balance = mAccount.GetBalance(); + double cRiskAmount = balance * cAmountPercent / 100; + double cRiskInPoints = risk / points; + double cVolume = mAccount.CalculateVolume( + signal.symbol, + cRiskAmount, + cRiskInPoints // + ); + cVolume = NormalizeVolume(cVolume, signal.symbol); + + // + if (cVolume > 0) + { + // + signal.ignoreEAVolume = ignoreEAVolume; + signal.volume = cVolume; + } + } + } + + // + // Draw Signal Oject ... + XCSignalObject *iSignalObj; + bool isCreated = mVisionCycleHelper + .mPOIDrawer + .DrawSignal(signal, iSignalObj); + if (isCreated) + { + // + mSignalDrawnObjects.Add(iSignalObj); + + // + int maxAllowedDrawnSignals = 15; + int count = mSignalDrawnObjects.Total(); + if (count > maxAllowedDrawnSignals) + { + // + int to = count - maxAllowedDrawnSignals; + mSignalDrawnObjects.DeleteRange( + 0, + to // + ); + } + } + } + + // + hasLong = false; + hasShort = false; + } + + // + mXWZConditions.Clean(); + + // + return result; + } + + /** + * Check for any Guard Actions ... + */ + bool CheckGuard( + X121SMCGuard &guards[], + const XPosition &positions[] // + ) override + { + // + bool result = false; + + // + Clean(guards); + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + // XWZ Guard Detection ... + if (useXWZSignal) + { + // + X121SMCGuard xwzGuards[]; + bool hasGuard = mXWZSignalDetector.DetectGuards( + xwzGuards, + positions, + cycleProvider // + ); + + // + if (hasGuard) + { + // + Copy( + xwzGuards, + guards, + false // + ); + } + + // + Clean(xwzGuards); + } + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + /** + * Update all Requirements without waiting ... + */ + void DoUnwaitedTicksWork() override + { + } + + /** + * Customize Strategy Identifier ... + */ + string GetTag() override + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + + // + // Props ... + CArrayObj mSignalDrawnObjects; + + // + // XC121SMCCycleHelper *mTriggerCycleHelper; + XC121SMCCycleHelper *mDecisionCycleHelper; + XC121SMCCycleHelper *mAnalyseCycleHelper; + XC121SMCCycleHelper *mVerificationCycleHelper; + XC121SMCCycleHelper *mConsolidationCycleHelper; + XC121SMCCycleHelper *mVisionCycleHelper; + + // + // Actions ... + + // + // Signalling Functions ... + + // + // XWZ Signal ... + bool DetectXWZSignal( + X121SMCStrategyConditions &conditions, + X121SMCStrategyXWZSignalConditions &xWZConditions // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = + // + mVisionCycleHelper != NULL && + mAnalyseCycleHelper != NULL && + mDecisionCycleHelper != NULL && + mConsolidationCycleHelper != NULL + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XWZ; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXWZSignalDetector.mConditions.setupTime; + bool isSetuped = mXWZSignalDetector.mConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXWZSignalDetector.mConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = mXWZSignalDetector.DetectSignalSetup( + cycleProvider // + ); + + // + setupDir = mXWZSignalDetector.mConditions.dir; + setupTime = mXWZSignalDetector.mConditions.setupTime; + + // + if (isSetuped) + { + // + int items = mXWZSignalDetector + .AddConditionsIfNotExists(); + + // + mXWZSignalDetector.mConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXWZSignalDetector.mConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXWZSignalConditions mTmpConditions[]; + Copy( + mXWZSignalDetector.mConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXWZSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = mXWZSignalDetector + .DetectSignalTrigger( + mTmpConditions[i], + cycleProvider // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXWZSignalDetector.mConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXWZSignalDetector.mConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + + // + Copy( + mConditions.targets, + conditions.targets // + ); + + // + xWZConditions = mConditions; + + // + mConditions.Clean(); + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mMaxAllowedRequiredPOIs; // Max Allowed Required POI(s) to Find ... + + /** + * Initial Required Indicators Helper ... + */ + void InitialHelpers() + { + // + useXWZSignal = true; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + if (mMaxAllowedRequiredPOIs <= 0) + { + mMaxAllowedRequiredPOIs = 0; + } + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES scPeriod = NULL; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES mcPeriod = NULL; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES lcPeriod = NULL; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES hcPeriod = NULL; // Time Period + + // + // XPV ... + X121Inputs x121Inputs; + + // + x121Inputs.Default(); + + // + bool showAll = false; + + // + x121Inputs.showRSI = false; + + // + // XPV ... + + // + x121Inputs.xpvInputs.scMethod = scMethod; + x121Inputs.xpvInputs.scPeriod = scPeriod; + x121Inputs.xpvInputs.mcMethod = mcMethod; + x121Inputs.xpvInputs.mcPeriod = mcPeriod; + x121Inputs.xpvInputs.lcMethod = lcMethod; + x121Inputs.xpvInputs.lcPeriod = lcPeriod; + x121Inputs.xpvInputs.hcMethod = hcMethod; + x121Inputs.xpvInputs.hcPeriod = hcPeriod; + + // + x121Inputs.xhkInputs.xhkIgnoreSmoothingShadows = true; + + // + x121Inputs.xatrInputs.atrMultiplier = 1.5; + x121Inputs.xatrInputs.atrSmoothingMode = X_MA_MODE_EMA; + + // + // XTREND ... + x121Inputs.xtrendInputs.showUpTrend = showAll || false; + x121Inputs.xtrendInputs.showDownTrend = showAll || false; + x121Inputs.xtrendInputs.showOnlyTrendStart = showAll || false; + + // + // XPV ... + x121Inputs.xpvInputs.showSar = showAll || true; + x121Inputs.xpvInputs.showPeaks = showAll || true; + x121Inputs.xpvInputs.showVales = showAll || true; + x121Inputs.xpvInputs.showGoldenZones = showAll || true; + + // + // XHK ... + + // + x121Inputs.xhkInputs.drawRawXHKCandles = showAll || false; + x121Inputs.xhkInputs.drawSmoothedXHKCandles = showAll || true; + + // + // XATR ... + x121Inputs.xatrInputs.showATRUpper = showAll || false; + x121Inputs.xatrInputs.showATRLower = showAll || false; + + // + // XSTR ... + x121Inputs.xstrInputs.showStr = showAll || false; + x121Inputs.xstrInputs.showStrUpper = showAll || false; + x121Inputs.xstrInputs.showStrLower = showAll || false; + + // + // XCHE ... + x121Inputs.xcheInputs.showLE1 = showAll || false; + x121Inputs.xcheInputs.showLE2 = showAll || false; + x121Inputs.xcheInputs.showSE1 = showAll || false; + x121Inputs.xcheInputs.showSE2 = showAll || false; + + // + // XDON ... + x121Inputs.xdonInputs.showOpen = showAll || false; + x121Inputs.xdonInputs.showClose = showAll || false; + x121Inputs.xdonInputs.showLow = showAll || false; + x121Inputs.xdonInputs.showHigh = showAll || false; + + // + // XVWAP ... + x121Inputs.xvwapInputs.showVWapFast = showAll || false; + x121Inputs.xvwapInputs.showVWapMedium = showAll || false; + x121Inputs.xvwapInputs.showVWapSlow = showAll || false; + + // + // X3MA ... + x121Inputs.x3maInputs.showX3MaFast = showAll || false; + x121Inputs.x3maInputs.showX3MaMid = showAll || false; + x121Inputs.x3maInputs.showX3MaSlow = showAll || false; + + // + // Initialize Cycle Helpers ... + + // + bool isInited = false; + + // + int requiredPOIS = MaxAllowedRequiredPOIs(); + + // + // Decision Cycle ... + mDecisionCycleHelper = new XC121SMCCycleHelper(); + isInited = mDecisionCycleHelper.Init( + symbol, + PERIOD_M5, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrDodgerBlue; + color bearishColor = clrSienna; + + // + // Bars ... + mDecisionCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mDecisionCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mDecisionCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mDecisionCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mDecisionCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mDecisionCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mDecisionCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mDecisionCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Analyse Cycle ... + mAnalyseCycleHelper = new XC121SMCCycleHelper(); + isInited = mAnalyseCycleHelper.Init( + symbol, + PERIOD_M15, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrMediumSeaGreen; + color bearishColor = clrBlueViolet; + + // + // Bars ... + mAnalyseCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mAnalyseCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mAnalyseCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mAnalyseCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mAnalyseCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mAnalyseCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mAnalyseCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mAnalyseCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Consolidation Cycle ... + mConsolidationCycleHelper = new XC121SMCCycleHelper(); + isInited = mConsolidationCycleHelper.Init( + symbol, + PERIOD_H1, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrLime; + color bearishColor = clrRed; + + // + // Bars ... + mConsolidationCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mConsolidationCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mConsolidationCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mConsolidationCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mConsolidationCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mConsolidationCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mConsolidationCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mConsolidationCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Vision Cycle ... + mVisionCycleHelper = new XC121SMCCycleHelper(); + isInited = mVisionCycleHelper.Init( + symbol, + PERIOD_H4, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrAqua; + color bearishColor = clrMagenta; + + // + // Bars ... + mVisionCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mVisionCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mVisionCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mVisionCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mVisionCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mVisionCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mVisionCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mVisionCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Initial Cycle Provider ... + cycleProvider.Init( + mDecisionCycleHelper, + mAnalyseCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // +}; + +// \ No newline at end of file