Entwicklung eines Replay Systems (Teil 43): Chart Trader Projekt (II)
Einführung
Im vorherigen Artikel Entwicklung eines Replay Systems (Teil 42): Chart Trader Project (I), habe ich gezeigt, wie Sie die Interaktion zwischen dem Mausindikator und anderen Indikatoren gestalten können.
Wir haben begonnen, Code zu schreiben, um sicherzustellen, dass der Chart Trade-Indikator in perfekter Harmonie mit dem Maus-Indikator existiert. Im Gegensatz zu den ersten Versionen des Chart Trade Indikators, die in den Artikeln beschrieben wurden, ist dies jedoch nicht der Fall:
- Entwicklung eines Expert Advisors für den Handel von Grund auf (Teil 30): CHART TRADE als Indikator?!
- Mehrere Indikatoren in einem Chart (Teil 06): Umwandlung von MetaTrader 5 in ein RAD-System (II)
- Mehrere Indikatoren in einem Chart (Teil 05): Umwandlung von MetaTrader 5 in ein RAD-System (I)
Hier werden wir etwas Fortgeschritteneres und daher etwas anderes machen. Das Ergebnis ist aber in jedem Fall dasselbe wie in Video 01. Ich schlage vor, dass Sie sich dieses Video ansehen, bevor Sie mit dem Lesen des Artikels beginnen, damit Sie eine Vorstellung davon bekommen, was wir genau tun werden. Das kann man nicht einfach durch Lesen des Codes verstehen. Man sagt, ein Bild sagt mehr als tausend Worte, also sehen Sie sich das Video an, um besser zu verstehen, was in diesem Artikel erklärt wird.
Video 01 - Demo-Video
Das Video zeigt, dass die Daten im Fenster Chart Trade angezeigt werden. Sie haben vielleicht bemerkt, dass wir alles genau so machen wie im vorherigen Artikel, aber die Informationen werden aktualisiert, ohne dass die Objekte tatsächlich verwendet werden. Und Sie fragen sich wahrscheinlich: Wie ist das möglich?
„Dieser Typ muss irgendeinen Trick anwenden. Ich habe noch nie jemanden gesehen, der so etwas tut. Das ergibt doch keinen Sinn...“ Andere denken wahrscheinlich, dass ich eine Art Zauberer oder Magier bin, mit Kräften jenseits der Vorstellungskraft. Nein, nichts dergleichen. Ich nutze einfach sowohl die MetaTrader 5-Plattform als auch die MQL5-Sprache auf einem Niveau, das viele Leute nicht verstehen wollen. Sie sagen und tun immer das Gleiche, ohne das wirkliche Potenzial und die Möglichkeiten der MQL5-Sprache oder der MetaTrader 5-Plattform zu erkunden.
Ich hoffe, alle haben das Video gesehen. Denn in diesem Artikel zeige ich Ihnen, wie Sie etwas tun können, das Ihr Denken darüber, was möglich und was unmöglich ist, grundlegend verändern wird. Das ist wichtig: Ich werde nur erklären, was in dem Video gezeigt wird. Die Dinge, die im Video nicht gezeigt werden, werden später besprochen.
Aktualisierung des Indikator-Codes
Die Änderungen, die vorgenommen werden müssen, werden nicht so groß sein. Aber wir werden trotzdem schrittweise vorankommen, weil sonst alle nicht mehr wissen, was eigentlich passiert.
Betrachten wir zunächst die Änderungen, die am Code des Indikators vorgenommen wurden. Die Änderungen sind im folgenden Code dargestellt.
Chart Trade Indikator Quellcode:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Base version for Chart Trade (DEMO version)" 04. #property version "1.43" 05. #property icon "/Images/Market Replay/Icons/Indicators.ico" 06. #property link "https://www.mql5.com/es/articles/11664" 07. #property indicator_chart_window 08. #property indicator_plots 0 09. //+------------------------------------------------------------------+ 10. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh> 11. //+------------------------------------------------------------------+ 12. C_ChartFloatingRAD *chart = NULL; 13. //+------------------------------------------------------------------+ 14. input int user01 = 1; //Leverage 15. input double user02 = 100.1; //Finance Take 16. input double user03 = 75.4; //Finance Stop 17. //+------------------------------------------------------------------+ 18. int OnInit() 19. { 20. chart = new C_ChartFloatingRAD("Indicator Chart Trade", new C_Mouse("Indicator Mouse Study"), user01, user02, user03); 21. if (_LastError != ERR_SUCCESS) 22. { 23. Print("Error number:", _LastError); 24. return INIT_FAILED; 25. } 26. 27. return INIT_SUCCEEDED; 28. } 29. //+------------------------------------------------------------------+ 30. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 31. { 32. return rates_total; 33. } 34. //+------------------------------------------------------------------+ 35. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 36. { 37. (*chart).DispatchMessage(id, lparam, dparam, sparam); 38. 39. ChartRedraw(); 40. } 41. //+------------------------------------------------------------------+ 42. void OnDeinit(const int reason) 43. { 44. delete chart; 45. 46. ChartRedraw(); 47. } 48. //+------------------------------------------------------------------+
Vergleichen Sie dies mit dem Quellcode des Indikators, der im Artikel Entwicklung eines Replay Systems (Teil 42); Chart Trader Project (I) angegeben wurde, können Sie sehen, dass es einige Änderungen erfahren hat. Wir haben eine Möglichkeit hinzugefügt, die es dem Nutzer ermöglicht, den Wert festzulegen, der anfänglich in den Indikator eingefügt werden soll. Obwohl wir diese Form der Interaktion zwischen den Zeilen 14 und 16 haben, sind diese Punkte nicht unbedingt notwendig, obwohl sie für Tests interessant sind. Denken Sie daran, dass Chart Trade ein System der Interaktion mit dem Nutzer ist.
Anstelle der Zeilen 14 bis 16 können Sie einfach den Standardwert in den Indikator eingeben. Dies kann in Zeile 20 geschehen, wo wir anstelle von Werten, die wir aus der Nutzerinteraktion erhalten, die Werte direkt in den Aufruf eingeben können. So haben wir Chart Trade mit Standardwerten, die vom Nutzer geändert werden können, nachdem der Indikator auf dem Chart erscheint.
Darauf soll in diesem Artikel nicht eingegangen werden. Der Grund dafür ist, dass wir dafür ein etwas anderes Verfahren verwenden. Aber wie Sie im Demo-Video sehen können, werden die vom Nutzer gemeldeten Werte an Chart Trade übertragen und übersichtlich dargestellt. Wie bereits erwähnt, ist das Vorhandensein einer solchen Wechselwirkung für Testzwecke interessant.
Wir haben gesehen, dass der Indikator in der Lage ist, eine Kommunikation herzustellen. Lassen Sie uns nun herausfinden, wie Sie Änderungen im Indikator vornehmen können, wie im Video gezeigt, allerdings ohne Objekte zu verwenden. Das einzige Objekt im Chart, das im Video zu sehen ist, ist OBJ_CHART. Hat jemand eine Idee, wie ich das geschafft habe? Wie habe ich Daten und Werte nur mit OBJ_CHART geändert?
Wenn Sie keine Ahnung haben, wie das möglich ist, müssen Sie studieren, wie die MetaTrader 5-Plattform und die MQL5-Sprache tatsächlich funktionieren. Um die Erklärung zu verdeutlichen, sollten wir ein neues Thema eröffnen.
Zielsetzung und Ziele
Die meisten Menschen, die programmieren lernen wollen oder davon träumen, haben eigentlich keine Ahnung, was sie da tun. Ihre Tätigkeit besteht darin, dass sie versuchen, Dinge auf eine bestimmte Art und Weise zu schaffen. Beim Programmieren geht es jedoch nicht darum, geeignete Lösungen zu finden. Auf diese Weise können mehr Probleme als Lösungen entstehen.
Vielleicht ist das nicht ganz klar. Nun, ich werde versuchen, ein wenig von meiner langjährigen Programmiererfahrung in verschiedenen Sprachen, Plattformen und Systemen zu vermitteln.
Wenn wir anfangen, ein System zu nutzen, was auch immer es sein mag, sollten wir als erstes seine Fähigkeiten bewerten und verstehen, was das System uns bietet. Dies ist eine allgemeine Aussage. Das heißt, wir müssen versuchen zu verstehen, warum alles so und nicht anders entstanden ist. Wenn Sie verstanden haben, wie die grundlegenden Funktionen funktionieren, können Sie sich in die Tiefe begeben.
Tiefer zu gehen bedeutet nicht, nach Möglichkeiten zu suchen, diese Funktionen zu verbessern oder einfach mit ihnen zu programmieren. Die Tiefe liegt in dem Versuch, die Ressourcen zu nutzen, die noch nicht von anderen erforscht wurden. Viele Menschen beschränken sich darauf, nur das zu nutzen, was alle anderen auch nutzen, und das ist nicht schlecht. Aber wie können Sie Verbesserungen vorschlagen, ohne sich nur oberflächlich mit den Möglichkeiten des Systems vertraut zu machen? Diese Art des Denkens macht keinen Sinn. Es ist, als würde ein Kind eine neue Produktionsmethode vorschlagen wollen, indem es sich ein laufendes Fließband ansieht. So etwas hat keine Zukunft und ist dazu verdammt, mehr Probleme als Lösungen zu schaffen.
Vielleicht habe ich mich noch nicht klar genug ausgedrückt. Wenn es um den MetaTrader 5 geht, meinen manche Leute, sie wüssten genug über die Plattform, um sagen zu können, was mit ihr möglich oder unmöglich ist. Und dann wenden sie sich an MQL5 und versuchen, einige ihrer Probleme zu lösen. Das ist ein Fehler. Sie sollten MQL5, wie jede andere Sprache auch, nicht als magischen Weg zur Befriedigung Ihrer Bedürfnisse oder Wünsche betrachten. MQL5 ist keine Zaubersprache. Diese Sprache erweitert die Möglichkeiten von MetaTrader 5. Sie ist jedoch nicht in der Lage, die Plattform anders arbeiten zu lassen als vorgesehen.
Die richtige Herangehensweise besteht darin, sich eingehend mit der Funktionsweise des MetaTrader 5 zu befassen und dann nach Möglichkeiten zu suchen, ihn an Ihre eigene Art der Marktbetrachtung und -analyse anzupassen. Bei der Erkundung von MetaTrader 5 werden Sie sehen, was Sie tun müssen, um ihn in ein Werkzeug zu verwandeln, das Ihrer Sicht des Marktes besser entspricht. Dazu müssen Sie MQL5 verwenden, das die Türen des MetaTrader 5 auf eine Weise öffnet, die Ihnen oder anderen Händlern das Leben erleichtert.
Vor diesem Hintergrund können wir uns eine Frage stellen. Viele Nutzer unterschätzen den MetaTrader 5, weil sie die grundlegenden Details seiner Funktionsweise nicht kennen. Eines dieser Details, und zwar nicht nur im MetaTrader 5, ist das Konzept der Vorlagen. Sie ermöglichen es uns, bestimmte Dinge auf einfache und praktische Art und Weise anzupassen, zu verändern und zu organisieren. Von Anmerkungen bis hin zur Vereinfachung des Prozesses, den Markt auf eine bestimmte Art und Weise zu einem bestimmten Zeitpunkt zu betrachten.
Vorlagen können eine Vielzahl von Dingen enthalten, und ich habe bereits gezeigt, wie man einige von ihnen erforscht. In dem Artikel Mehrere Indikatoren in einem Chart (Teil 03): Entwicklung von Definitionen für die Nutzer habe ich gezeigt, wie verschiedene Indikatoren nebeneinander platziert werden können, wie in Abbildung 01 dargestellt.
Abbildung 01 - Verwendung mehrerer Indikatoren in einem Teilfenster
Das oben dargestellte Konzept ist nur mit Vorlagen möglich. Ganz gleich, wie gut Sie programmieren können und wie umfangreich Ihre Kenntnisse über MQL5 sind, Sie werden niemals das in Abbildung 01 gezeigte Ergebnis erzielen können, wenn Sie nicht verstehen, wie MetaTrader 5 funktioniert. Das liegt daran, dass nicht alles auf das Schreiben von Code hinausläuft. Programmieren hilft nur, eine Lösung zu finden, die sonst nicht möglich wäre. Es sollte jedoch nicht der erste Versuch sein, wenn man etwas Neues braucht, sondern eher ein Werkzeug, um das gewünschte Ergebnis zu erzielen.
Warum sage ich das? Der Grund dafür ist genau das, was in Video 01 am Anfang dieses Artikels gezeigt wird. Egal wie gut Sie programmieren können oder verstehen, wie MQL5 funktioniert, Sie werden nicht in der Lage sein, das zu tun, was in dem Video gezeigt wird, ohne zu verstehen, wie MetaTrader 5 funktioniert.
Ein wichtiger Punkt dieser Geschichte ist, dass ich bei der Veröffentlichung des Artikels „Mehrere Indikatoren auf einem Chart (Teil 06): Verwandlung von MetaTrader 5 in ein RAD-System (II)“, damals habe ich bestimmte MetaTrader 5-Konzepte noch nicht verwendet. Ich steckte noch immer in einigen Ideen und Konzepten fest, die sich schließlich als ungeeignet erwiesen. Ich will damit nicht sagen, dass sie falsch waren, aber sie waren weniger geeignet. Es gibt viel bessere Lösungen. Dies ist genau auf das zurückzuführen, was in diesem Artikel sowie im vorhergehenden Artikel „Mehrere Indikatoren in einem Chart (Teil 05): Umwandlung von MetaTrader 5 in ein RAD-System (I)“ gezeigt wurde.
In beiden Fällen haben wir die Vorlage geöffnet und versucht, sie zu bearbeiten. Aber all diese Arbeit war nicht mehr als ein Kratzer an der Oberfläche, denn vieles von dem, was Sie sehen, ist eine Neuprogrammierung derselben Vorlage. Dies geschah so, dass das RAD-System emuliert wurde, das durch Programmierung in MQL5 implementiert werden kann.
Obwohl dies funktioniert hat, werden Sie feststellen, dass die Vorlage, die wie in MetaTrader 5 erstellt wurde, später vom Indikator selbst neu erstellt wurde, als der Indikator auf dem Chart platziert wurde. Folglich wurden alle Objekte, die in der Vorlage vorhanden waren, durch den Indikator neu erstellt. Auf diese Weise erhielt MetaTrader 5 Zugang zu den dort befindlichen Objekten und konnte die darin enthaltenen Werte konfigurieren und ändern.
Im Laufe der Zeit wurde jedoch deutlich, dass die Idee verbessert werden konnte. Daher habe ich ein geeigneteres Chart Trade-Modell gefunden, das ein Minimum an Objekten verwendet. Nun, wir müssen noch etwas mehr tun als das, was in diesem Artikel gezeigt wird. Das Video 01 zeigt jedoch, dass sich die Werte geändert haben. Gleichzeitig haben wir nur ein Objekt auf dem Bildschirm.
Genau das ermöglicht uns das Programmieren. Ohne sie wären wir auf das beschränkt, was in MetaTrader 5 verfügbar ist. Durch Programmierung erweitern wir die Möglichkeiten der Plattform. Dies wird erreicht, indem wir nutzen, was bereits in MetaTrader 5 vorhanden ist. Wir erstellen eine Vorlage mit genau dem, was wir brauchen, und platzieren sie in OBJ_CHART. Ohne entsprechende Programmierung wäre es jedoch unmöglich, die Werte in den Objekten innerhalb der Vorlage zu ändern. Durch die richtige Programmierung lösen wir dieses Problem und erweitern so die Möglichkeiten des MetaTrader 5.
Um dies zu verdeutlichen, öffnen Sie die in Chart Trade verwendete Vorlagendatei. Er wird im Folgenden vollständig wiedergegeben.
Chart Trade Datei (Vorlage):
001. <chart> 002. fore=0 003. grid=0 004. volume=0 005. ticker=0 006. ohlc=0 007. one_click=0 008. one_click_btn=0 009. bidline=0 010. askline=0 011. lastline=0 012. descriptions=0 013. tradelines=0 014. tradehistory=0 015. background_color=16777215 016. foreground_color=0 017. barup_color=16777215 018. bardown_color=16777215 019. bullcandle_color=16777215 020. bearcandle_color=16777215 021. chartline_color=16777215 022. volumes_color=16777215 023. grid_color=16777215 024. bidline_color=16777215 025. askline_color=16777215 026. lastline_color=16777215 027. stops_color=16777215 028. windows_total=1 029. 030. <window> 031. height=100.000000 032. objects=18 033. 034. <indicator> 035. name=Main 036. path= 037. apply=1 038. show_data=1 039. scale_inherit=0 040. scale_line=0 041. scale_line_percent=50 042. scale_line_value=0.000000 043. scale_fix_min=0 044. scale_fix_min_val=0.000000 045. scale_fix_max=0 046. scale_fix_max_val=0.000000 047. expertmode=0 048. fixed_height=-1 049. </indicator> 050. 051. <object> 052. type=110 053. name=MSG_NULL_000 054. color=0 055. pos_x=0 056. pos_y=0 057. size_x=170 058. size_y=210 059. bgcolor=16777215 060. refpoint=0 061. border_type=1 062. </object> 063. 064. <object> 065. type=110 066. name=MSG_NULL_001 067. color=0 068. pos_x=5 069. pos_y=30 070. size_x=152 071. size_y=26 072. bgcolor=12632256 073. refpoint=0 074. border_type=1 075. </object> 076. 077. <object> 078. type=110 079. name=MSG_NULL_002 080. color=0 081. pos_x=5 082. pos_y=58 083. size_x=152 084. size_y=26 085. bgcolor=15130800 086. refpoint=0 087. border_type=1 088. </object> 089. 090. <object> 091. type=110 092. name=MSG_NULL_003 093. color=0 094. pos_x=5 095. pos_y=86 096. size_x=152 097. size_y=26 098. bgcolor=10025880 099. refpoint=0 100. border_type=1 101. </object> 102. 103. <object> 104. type=110 105. name=MSG_NULL_004 106. color=0 107. pos_x=5 108. pos_y=114 109. size_x=152 110. size_y=26 111. bgcolor=8036607 112. refpoint=0 113. border_type=1 114. </object> 115. 116. <object> 117. type=102 118. name=MSG_NULL_007 119. descr=Lever ( x ) 120. color=0 121. style=1 122. angle=0 123. pos_x=10 124. pos_y=63 125. fontsz=16 126. fontnm=System 127. anchorpos=0 128. refpoint=0 129. </object> 130. 131. <object> 132. type=102 133. name=MSG_NULL_008 134. descr=Take ( $ ) 135. color=0 136. style=1 137. angle=0 138. pos_x=10 139. pos_y=91 140. fontsz=16 141. fontnm=System 142. anchorpos=0 143. refpoint=0 144. </object> 145. 146. <object> 147. type=102 148. name=MSG_NULL_009 149. descr=Stop ( $ ) 150. color=0 151. style=1 152. angle=0 153. pos_x=10 154. pos_y=119 155. fontsz=16 156. fontnm=System 157. anchorpos=0 158. refpoint=0 159. </object> 160. 161. <object> 162. type=107 163. name=MSG_TITLE_IDE 164. descr=Chart Trade 165. color=16777215 166. style=1 167. pos_x=0 168. pos_y=0 169. size_x=164 170. size_y=28 171. bgcolor=16748574 172. fontsz=16 173. fontnm=System 174. refpoint=0 175. readonly=1 176. align=0 177. </object> 178. 179. <object> 180. type=106 181. name=MSG_BUY_MARKET 182. size_x=70 183. size_y=25 184. offset_x=0 185. offset_y=0 186. pos_x=5 187. pos_y=145 188. bmpfile_on=\Images\Market Replay\Chart Trade\BUY.bmp 189. bmpfile_off=\Images\Market Replay\Chart Trade\BUY.bmp 190. state=0 191. refpoint=0 192. anchorpos=0 193. </object> 194. 195. <object> 196. type=106 197. name=MSG_SELL_MARKET 198. size_x=70 199. size_y=25 200. offset_x=0 201. offset_y=0 202. pos_x=85 203. pos_y=145 204. bmpfile_on=\Images\Market Replay\Chart Trade\SELL.bmp 205. bmpfile_off=\Images\Market Replay\Chart Trade\SELL.bmp 206. state=0 207. refpoint=0 208. anchorpos=0 209. </object> 210. 211. <object> 212. type=103 213. name=MSG_CLOSE_POSITION 214. descr=Close Position 215. color=0 216. style=1 217. pos_x=5 218. pos_y=173 219. fontsz=16 220. fontnm=System 221. state=0 222. size_x=152 223. size_y=26 224. bgcolor=1993170 225. frcolor=-1 226. refpoint=0 227. </object> 228. 229. <object> 230. type=107 231. name=MSG_NAME_SYMBOL 232. descr=? 233. color=0 234. style=1 235. pos_x=7 236. pos_y=34 237. size_x=116 238. size_y=20 239. bgcolor=12632256 240. fontsz=14 241. fontnm=Tahoma 242. refpoint=0 243. readonly=1 244. align=1 245. </object> 246. 247. <object> 248. type=107 249. name=MSG_LEVERAGE_VALUE 250. descr=? 251. color=0 252. style=1 253. pos_x=80 254. pos_y=61 255. size_x=70 256. size_y=18 257. bgcolor=15130800 258. fontsz=12 259. fontnm=Tahoma 260. refpoint=0 261. readonly=0 262. align=1 263. </object> 264. 265. <object> 266. type=107 267. name=MSG_TAKE_VALUE 268. descr=? 269. color=0 270. style=1 271. pos_x=80 272. pos_y=91 273. size_x=70 274. size_y=18 275. bgcolor=10025880 276. fontsz=12 277. fontnm=Tahoma 278. refpoint=0 279. readonly=0 280. align=1 281. </object> 282. 283. <object> 284. type=107 285. name=MSG_STOP_VALUE 286. descr=? 287. color=0 288. style=1 289. pos_x=80 290. pos_y=119 291. size_x=70 292. size_y=18 293. bgcolor=8036607 294. fontsz=12 295. fontnm=Tahoma 296. refpoint=0 297. readonly=0 298. align=1 299. </object> 300. 301. <object> 302. type=106 303. name=MSG_DAY_TRADE 304. size_x=32 305. size_y=22 306. offset_x=0 307. offset_y=0 308. pos_x=123 309. pos_y=33 310. bmpfile_on=\Images\Market Replay\Chart Trade\DT.bmp 311. bmpfile_off=\Images\Market Replay\Chart Trade\SW.bmp 312. state=0 313. refpoint=0 314. anchorpos=0 315. </object> 316. 317. <object> 318. type=106 319. name=MSG_MAX_MIN 320. size_x=20 321. size_y=20 322. offset_x=0 323. offset_y=0 324. pos_x=140 325. pos_y=3 326. bmpfile_on=\Images\Market Replay\Chart Trade\Maximize.bmp 327. bmpfile_off=\Images\Market Replay\Chart Trade\Minimize.bmp 328. state=1 329. refpoint=0 330. anchorpos=0 331. </object> 332. 333. </window> 334. </chart>
Ich weiß, der Inhalt mag völlig unnötig erscheinen. Bitte beachten Sie, dass es keine Dateien im Anhang geben wird. Das gesamte System wird so veröffentlicht, dass die Dateien durch Umschreiben der Codes in die entsprechenden Dateien erhalten werden können. Ich tue dies, um sicherzustellen, dass Sie den Artikel lesen und verstehen. Ich möchte nicht, dass Sie die angehängten Dateien einfach herunterladen und das System nutzen, ohne zu wissen, was Sie tun. Auch wenn es den Anschein hat, dass der Artikel dadurch wesentlich länger wird, ist das nicht der Fall, sondern die Erklärung wird nur viel ausführlicher.
Schauen wir uns nun die Chart Trade-Vorlagendatei genauer an. Achten Sie auf die Zeilen mit den folgenden Angaben:
descr=?
Sie kommt an mehreren Stellen in der Vorlagendatei vor und ist absichtlich so gewählt. Warum? Obwohl descr an verschiedenen Stellen erscheint, beziehen sich diese Stellen, wie oben gezeigt, hauptsächlich auf Objekte des Typs 107. Was sind Objekte des Typs 107?
Eine Beschreibung dieser Arten von Objekten erschien zuerst im Artikel „Mehrere Indikatoren in einem Chart (Teil 05): MetaTrader 5 in ein RAD (I)-System verwandeln“. Der Einfachheit halber werde ich die in diesem Artikel vorgestellte Tabelle nachstehend wiedergeben:
Der Wert der Variablen TYPE | Referenziertes Objekt |
---|---|
102 | OBJ_LABEL |
103 | OBJ_BUTTON |
106 | OBJ_BITMAP_LABEL |
107 | OBJ_EDIT |
110 | OBJ_RECTANGLE_LABEL |
Objekt 107 ist also OBJ_EDIT. Dies sind Objekte, in die der Nutzer Informationen eingeben kann.
Es ist jedoch nicht möglich, direkt auf ein Objekt zuzugreifen, das sich in einer Vorlage befindet, oder dort einen Wert einzugeben. Das ist eine Tatsache. Wie habe ich dieses Problem gelöst, sodass das in der Vorlage vorhandene Objekt 107 Werte vom Indikator erhalten kann? Um diese Frage zu beantworten, müssen Sie sich den Code der Klasse ansehen, die für die Verwendung der Vorlage verantwortlich ist.
Aktualisieren der Klasse C_ChartFloatingRAD
Damit Chart Trade die vom Nutzer eingegebenen Werte anzeigt, müssen Sie unmittelbar nach dem Start des Indikators im Chart einige grundlegende Operationen durchführen. Diese Operationen zielen darauf ab, bestimmte Probleme zu lösen, die ohne den Einsatz von Programmierung nicht gelöst werden können. Aus diesem Grund ist es sehr wichtig, dass Sie die Funktionsweise des MetaTrader 5 gut verstehen. Ohne die Prinzipien der Plattformbedienung zu kennen, werden Sie nicht in der Lage sein, den erforderlichen Code zu erstellen, um solche Hindernisse zu überwinden, die ohne Programmierung nicht zu lösen sind.
Der vollständige Code für die Klasse C_ChartFloatingRAD ist unten zu sehen. Dieser Code in seiner jetzigen Form ermöglicht es dem Indikator, wie in Video 01 gezeigt zu funktionieren. Können Sie verstehen, wie das geschieht?
Quellcode der Klasse C_ChartFloatingRAD:
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. //+------------------------------------------------------------------+ 004. #include "../Auxiliar/C_Terminal.mqh" 005. #include "../Auxiliar/C_Mouse.mqh" 006. //+------------------------------------------------------------------+ 007. class C_ChartFloatingRAD : private C_Terminal 008. { 009. private : 010. struct st00 011. { 012. int x, y, cx, cy; 013. string szObj_Chart, 014. szFileNameTemplate; 015. long WinHandle; 016. double FinanceTake, 017. FinanceStop; 018. int Leverage; 019. }m_Info; 020. //+------------------------------------------------------------------+ 021. C_Mouse *m_Mouse; 022. //+------------------------------------------------------------------+ 023. void CreateWindowRAD(int x, int y, int w, int h) 024. { 025. m_Info.szObj_Chart = (string)ObjectsTotal(GetInfoTerminal().ID); 026. ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0); 027. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x = x); 028. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y = y); 029. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w); 030. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h); 031. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false); 032. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false); 033. m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID); 034. m_Info.cx = w; 035. m_Info.cy = 26; 036. }; 037. //+------------------------------------------------------------------+ 038. void Level_1(int &fpIn, int &fpOut, const string szFind, const string szWhat, const string szValue) 039. { 040. string sz0 = ""; 041. int i0 = 0; 042. string res[]; 043. 044. while ((!FileIsEnding(fpIn)) && (sz0 != "</object>")) 045. { 046. sz0 = FileReadString(fpIn); 047. if (StringSplit(sz0, '=', res) > 1) 048. { 049. i0 = (res[1] == szFind ? 1 : i0); 050. if ((i0 == 1) && (res[0] == szWhat)) 051. { 052. FileWriteString(fpOut, szWhat + "=" + szValue + "\r\n"); 053. return; 054. } 055. } 056. FileWriteString(fpOut, sz0 + "\r\n"); 057. }; 058. } 059. //+------------------------------------------------------------------+ 060. void SwapValueInTemplate(const string szFind, const string szWhat, const string szValue) 061. { 062. int fpIn, fpOut; 063. string sz0; 064. 065. if (_LastError != ERR_SUCCESS) return; 066. if ((fpIn = FileOpen(m_Info.szFileNameTemplate, FILE_READ | FILE_TXT)) == INVALID_HANDLE) 067. { 068. SetUserError(C_Terminal::ERR_FileAcess); 069. return; 070. } 071. if ((fpOut = FileOpen(m_Info.szFileNameTemplate + "_T", FILE_WRITE | FILE_TXT)) == INVALID_HANDLE) 072. { 073. FileClose(fpIn); 074. SetUserError(C_Terminal::ERR_FileAcess); 075. return; 076. } 077. while (!FileIsEnding(fpIn)) 078. { 079. sz0 = FileReadString(fpIn); 080. FileWriteString(fpOut, sz0 + "\r\n"); 081. if (sz0 == "<object>") Level_1(fpIn, fpOut, szFind, szWhat, szValue); 082. }; 083. FileClose(fpIn); 084. FileClose(fpOut); 085. if (!FileMove(m_Info.szFileNameTemplate + "_T", 0, m_Info.szFileNameTemplate, FILE_REWRITE)) 086. { 087. FileDelete(m_Info.szFileNameTemplate + "_T"); 088. SetUserError(C_Terminal::ERR_FileAcess); 089. } 090. } 091. //+------------------------------------------------------------------+ 092. inline void UpdateChartTemplate(void) 093. { 094. ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate); 095. ChartRedraw(m_Info.WinHandle); 096. } 097. //+------------------------------------------------------------------+ 098. inline double PointsToFinance(const double Points) 099. { 100. return Points * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.Leverage - 1))) * GetInfoTerminal().AdjustToTrade; 101. }; 102. //+------------------------------------------------------------------+ 103. public : 104. //+------------------------------------------------------------------+ 105. C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const int Leverage, const double FinanceTake, const double FinanceStop) 106. :C_Terminal() 107. { 108. m_Mouse = MousePtr; 109. m_Info.Leverage = (Leverage < 0 ? 1 : Leverage); 110. m_Info.FinanceTake = PointsToFinance(FinanceToPoints(MathAbs(FinanceTake), m_Info.Leverage)); 111. m_Info.FinanceStop = PointsToFinance(FinanceToPoints(MathAbs(FinanceStop), m_Info.Leverage)); 112. if (!IndicatorCheckPass(szShortName)) SetUserError(C_Terminal::ERR_Unknown); 113. m_Info.szFileNameTemplate = StringFormat("Chart Trade/%u.tpl", GetInfoTerminal().ID); 114. if (!FileCopy("Chart Trade/IDE_RAD.tpl", 0, m_Info.szFileNameTemplate, FILE_REWRITE)) SetUserError(C_Terminal::ERR_FileAcess); 115. if (_LastError != ERR_SUCCESS) return; 116. SwapValueInTemplate("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol); 117. SwapValueInTemplate("MSG_LEVERAGE_VALUE", "descr", (string)m_Info.Leverage); 118. SwapValueInTemplate("MSG_TAKE_VALUE", "descr", (string)m_Info.FinanceTake); 119. SwapValueInTemplate("MSG_STOP_VALUE", "descr", (string)m_Info.FinanceStop); 120. if (_LastError != ERR_SUCCESS) return; 121. CreateWindowRAD(0, 0, 170, 210); 122. UpdateChartTemplate(); 123. } 124. //+------------------------------------------------------------------+ 125. ~C_ChartFloatingRAD() 126. { 127. ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Chart); 128. FileDelete(m_Info.szFileNameTemplate); 129. 130. delete m_Mouse; 131. } 132. //+------------------------------------------------------------------+ 133. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 134. { 135. static int sx = -1, sy = -1; 136. int x, y, mx, my; 137. 138. switch (id) 139. { 140. case CHARTEVENT_MOUSE_MOVE: 141. if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) 142. { 143. x = (int)lparam; 144. y = (int)dparam; 145. if ((x > m_Info.x) && (x < (m_Info.x + m_Info.cx)) && (y > m_Info.y) && (y < (m_Info.y + m_Info.cy))) 146. { 147. if (sx < 0) 148. { 149. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false); 150. sx = x - m_Info.x; 151. sy = y - m_Info.y; 152. } 153. if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x = mx); 154. if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y = my); 155. } 156. }else if (sx > 0) 157. { 158. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true); 159. sx = sy = -1; 160. } 161. break; 162. } 163. } 164. //+------------------------------------------------------------------+ 165. }; 166. //+------------------------------------------------------------------+
Bitte beachten Sie, dass die Datei C_ChartFloatingRAD seit dem letzten Artikel praktisch keine wesentlichen Ergänzungen erfahren hat. Dies ist beabsichtigt. Wenn ich Ihnen die endgültige Version dieser Datei zeigen würde, könnten Sie nicht verstehen, wie und warum MetaTrader 5 es schafft, die Werte in der Vorlage zu ändern. Dies geschieht, damit Sie beim Öffnen des Objektlistenfensters mit STRG+B nur OBJ_CHART in der Liste sehen, aber die Werte und das Fenster trotzdem geändert werden.
Versuchen wir nun zu verstehen, wie und warum der MetaTrader 5 uns über das Geschehen in einem Template informieren kann. Denken Sie daran, dass die Vorlage weiter verwendet wird und auf das Objekt OBJ_CHART angewendet wird. Dies geschieht, wenn Zeile 94 ausgeführt wird und Zeile 95 MetaTrader 5 anweist, OBJ_CHART zu aktualisieren. Wenn Sie diese Tatsache nicht berücksichtigen, können Sie viel Zeit damit verbringen, etwas im Code zu suchen, das nicht vorhanden ist. Zum Beispiel für die Dinge, die tatsächlich in der Vorlagendatei stehen.
Der hinzugefügte Code ist zwischen den Zeilen 38 und 123 zu sehen. Er ist so aufgebaut, dass die weiteren Schritte, die im nächsten Artikel durchgeführt werden, keine großen Änderungen erfordern, was sehr gut ist. Achten Sie also auf die Erklärungen in diesem Artikel, und Sie werden die nächste sehr leicht verstehen. Vielleicht können Sie sogar vorhersagen, was im nächsten Artikel aus der Sicht der Programmierung getan werden wird.
Beginnen wir mit dem Klassenkonstruktor, da dies das Verständnis der anderen Teile wesentlich erleichtert. Dieser Konstruktor beginnt in Zeile 105. Aber die wirkliche Veränderung beginnt in Zeile 109. In dieser Zeile garantieren wir, dass der Wert der Hebelwirkung immer größer oder gleich 1 sein wird. Hierfür verwenden wir den ternären Operator. Hier gibt es also nichts besonders Kompliziertes oder Verwirrendes.
Gehen wir nun zu Zeile 110. In dieser Zeile wird, wie in Zeile 111, eine Anpassung des im Chart Trade-Fenster angezeigten Wertes vorgenommen. Der Grund dafür ist, dass der Nutzer einen Wert eingeben kann, der nicht für den Vermögenswert gültig ist, für den der Chart Trade Indikator läuft. Im Falle von Dollar-Futures beispielsweise erfolgen die Bewegungen immer alle 5,00 $ pro Kontrakt. In diesem Fall ist die Angabe von Take-Profit oder Stop-Loss als Wert, der kein Vielfaches von 5 ist, z. B. Take-Profit=R$76,00, nicht sinnvoll, da dieser Wert nie erreicht wird.
Die Zeilen 110 und 111 führen also zwei Gespräche. Die erste wandelt den finanziellen Wert in Punkte um, die zweite macht das Gegenteil und wandelt den Punktwert in einen finanziellen Wert um. Man könnte meinen, dass dies den Wert auf seinen ursprünglichen Wert zurücksetzt. Das ist richtig, aber hier werden mathematische Methoden zur Umrechnung und Anpassung der Werte verwendet. Beim ersten Aufruf wird die Funktion in der Klasse C_Terminal verwendet. In der zweiten führen wir die Funktion aus, die in Zeile 98 steht.
Diese Funktion bei 98 benötigt nur eine Zeile. In Zeile 100 wird eine Berechnung durchgeführt, die die angegebene Anzahl von Pips in einen finanziellen Wert umwandelt.
Das war der einfache Teil. Betrachten wir nun den schwierigsten Teil des derzeitigen Systems.
Sobald der Konstruktor die Zeile 113 erreicht, erhalten wir etwas sehr Interessantes. In dieser Zeile 113 wird der Name der temporären Datei erstellt. Denken Sie daran, dass diese Datei nur vorübergehend ist. Sie befindet sich in dem in MQL5\Files definierten Bereich zusammen mit anderen Informationen, die speziell für diese Zeile 113 erstellt wurden.
Sobald wir den Dateinamen in Zeile 113 erstellt haben, gehen wir zu Zeile 114 über. In dieser Zeile wird der Inhalt der Vorlagendatei (die im vorherigen Thema zu sehen ist) vollständig unter einem neuen Namen kopiert. Wenn wir Erfolg haben, werden wir weitermachen. Wenn das Kopieren jedoch fehlschlägt, werden wir dies dem Initiator mitteilen.
Der eigentliche Zauber findet zwischen den Zeilen 116 und 119 statt. Hier sorgen wir dafür, dass der Chart Trade-Indikator die vom MetaTrader 5 und/oder dem Nutzer bereitgestellten Werte empfängt. Diese Zeilen rufen die Zeile 60 des Klassencodes auf. Von nun an werden wir an diesem Teil des Codes arbeiten, da der Rest des Konstruktors im vorherigen Artikel erklärt wurde. Bevor wir jedoch zu Zeile 60 übergehen, möchte ich Ihre Aufmerksamkeit auf eine weitere Zeile lenken, die dem Code hinzugefügt wurde: Zeile 128. Dort wird die im Konstruktor erstellte Datei gelöscht. Deshalb habe ich betont, dass die erstellte Datei temporär ist.
Gehen wir weiter zu Zeile 60. Ich muss hier etwas wiederholen (ich bin noch dabei, die Grundlagen zu erklären, haben Sie also etwas Geduld). Der erste Schritt besteht darin, die „Original“-Datei zu öffnen (beachten Sie die Anführungszeichen in dem Wort); dies geschieht in Zeile 66. Wenn wir Erfolg haben, werden wir weitermachen. Wenn wir scheitern, kehren wir zum Anrufer zurück.
In Zeile 71 erstellen wir eine temporäre Datei aus einer temporären Datei (klingt seltsam, aber anders kann man es nicht sagen). Wenn dies fehlschlägt, schließen wir die geöffnete Datei und kehren zum Aufrufer zurück. Bis Zeile 77 haben wir nur eine Datei geöffnet und eine weitere erstellt. Wenn die Ausführung die Zeile 77 erreicht, wird eine Schleife gestartet, um die gesamte Datei zu kopieren.
Moment, die gesamte Datei kopieren? Schon wieder? Ja, aber dieses Mal werden wir eine Bedingung in Zeile 81 testen. Diese Bedingung prüft, ob ein Objekt in der Vorlagendatei während des Kopiervorgangs gefunden wurde. Wenn dies geschieht, gehen wir zu Zeile 38 über, wo wir uns mit dem gefundenen Objekt befassen. Wenn es sich bei dem analysierten Muster um ein Muster aus dem vorherigen Thema handelt, springen wir in jedem Fall zu Zeile 38. Auch wenn Sie Ihre eigene Vorlage verwenden möchten, können Sie dies tun, solange Sie die Namen der Objekte korrekt definieren.
Nach dem Aufruf der in Zeile 38 vorgestellten Funktion gehen wir weiter bis zur Zeile 44. Hier setzen wir das Kopieren der Datei auf die gleiche Weise fort wie zuvor. Wenn jedoch die Zeile, die das Objekt schließt, genau in dieser Zeile 44 zu finden ist, kehren wir zum aufrufenden Objekt zurück, d. h. zur Zeile 81. Halten wir einen Moment inne und sehen uns die Funktion an, die in Zeile 38 erscheint.
Während des Kopiervorgangs lesen wir die Quelldatei in Zeile 46. Danach werden wir den Inhalt dieser Zeile erweitern. Wenn Zeile 47, die diese Zerlegung durchführt, meldet, dass zwei Anweisungen verfügbar sind, wird ein neuer Ausführungsfaden erstellt. Andernfalls wird die gelesene Zeile geschrieben, und das geschieht in Zeile 56.
Beachten Sie nun den folgenden Punkt: Bei der in Zeile 47 durchgeführten Zerlegung hat die Variable i0 den Anfangswert 0. Achten Sie hierauf besonders. Sobald der Objektname gefunden ist, wird die Variable i0 auf 1 gesetzt. Genau hier liegt die Gefahr. Wenn Sie eine Vorlagendatei manuell bearbeiten, müssen Sie sicherstellen, dass der Objektname vor den Parametern erscheint. Der einzige Parameter, der vor dem Namen erscheinen kann, ist der Typ des Objekts. Vor dem Namen sollten keine weiteren Parameter stehen. Wenn dies geschieht, wird der gesamte Prozess fehlschlagen.
In Zeile 50 wird geprüft, ob i0 anzeigt, dass das gewünschte Objekt gefunden wurde. In diesem Fall ist der Wert dieser Variablen 1. Es gibt aber noch eine zweite Bedingung, die den gesuchten Parameter betrifft. In diesem Fall suchen wir immer nach descr. Wenn diese beiden Bedingungen erfüllt sind, schreiben wir den gewünschten Wert während des Kopiervorgangs. Diese Art der Änderung erfolgt in Zeile 52. Danach kehren wir zum Aufrufer zurück, d. h. zur Zeile 81.
Beobachten Sie, wie dieser Prozess abläuft. Wir kopieren die gesamte Datei, mit Ausnahme einer bestimmten Zeile. Diese Zeile wird geändert, sodass neue Daten in der Vorlage erscheinen oder diese ein anderes Aussehen erhält.
Wenn die gesamte Datei kopiert und geändert wurde, schließen wir beide Dateien, was in den Zeilen 83 und 84 geschieht. Danach, in Zeile 85, versuchen wir, die temporäre Datei in die Datei umzubenennen, die die Klasse zu verwenden erwartet. Der Vorgang ist genau derselbe wie in Video 01 gezeigt.
Schlussfolgerung
In diesem Material habe ich die ersten Schritte erläutert, die Sie befolgen müssen, um die Vorlage verwalten zu können. Auf diese Weise passt es sich an unsere Bedürfnisse an. Dadurch können wir die Möglichkeiten von MetaTrader 5 mit einer relativ einfachen Programmierung besser nutzen. Wichtig ist jedoch, dass Sie nicht mehr oder weniger Objekte auf dem Chart verwenden. Was wirklich wichtig ist, ist zu verstehen, dass MQL5 es jedem ermöglicht, MetaTrader 5 in eine Plattform zu verwandeln, die für seine Bedürfnisse geeignet ist, und nicht, eine andere konkurrierende Plattform zu schaffen.
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/11664
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.