
リプレイシステムの開発(第43回):Chart Traderプロジェクト(II)
はじめに
前回の「リプレイシステムの開発(第42回):Chart Traderプロジェクト(I)」では 、マウス指標と他の指標の相互作用をアレンジする方法を紹介しました。
Chart Trade指標がマウス指標と完璧に調和するようにコードを書き始めました。しかし、このChart Trade指標の最初のバージョンでおこなわれたこととは異なります。
- 一からの取引エキスパートアドバイザーの開発(第30部):指標としてのChart Trade?
- 単一チャート上の複数インジケータ(第06部):MetaTrader 5をRADシステムに変える(II)
- 単一チャート上の複数インジケータ(第05部):MetaTrader 5をRADシステムに変える(I)
ここでは、より高度で、それゆえに異なることをしますが、いずれにせよ、結果はビデオ01と同じになります。記事を読み始める前に、このビデオを見て、これから何をするのかをイメージしておくことをお勧めします。これはコードを読んだだけで理解できるものではありません。百聞は一見にしかずという通り、記事で説明されることをよりよく理解するためにビデオをご覧ください。
ビデオ01:デモビデオ
ビデオでは、Chart Tradeウィンドウでのデータの表示を示しています。お気づきかもしれませんが、前回の記事で紹介したとおりにすべておこなっています。なのに、実際にオブジェクトを使用することなく情報が更新されています。何故こんなことが可能なのか疑問に思われている方もいるかもしれません。
「この男は何か策略を巡らせているに違いない。こんなことをする人は見たことがない。これはいったい何なんだ.....」他の読者は、私が想像を超える力を持った魔術師かマジシャンの一種だと思っているかもしれません。いや、こんなことはありません。私はMetaTrader 5プラットフォームとMQL5言語の両方を、多くの人が理解しようと努力しないレベルで使用しているだけです。彼らは、MQL5言語やMetaTrader 5プラットフォームの真の可能性や能力を探求することなく、いつも同じことを言い続け、実行し続けます。
皆さん、ビデオをご覧になってください。この記事では、何が可能で何が不可能かについての考え方を根本から変える方法を紹介するからです。重要:ビデオに映っていることだけを説明します。ビデオに映っていないことについては後述します。
指標コードの更新
必要な変化はそれほど大きくないでしょう。しかし、それでもゆっくりと前進していくつもりです。そうでなければ、何が起こっているのか、誰もが明確に理解できないまま取り残されてしまうでしょう。
まず、指標のコードに加えられた変更点を見てみましょう。変更点は以下のコードに示されています。
Chart Trade指標のソースコード
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. //+------------------------------------------------------------------+
「リプレイシステムの開発(第42回):Chart Traderプロジェクト(I)」で紹介した指標のソースコードと比較してみると、いくつかの変更が加えられたことがわかります。指標に最初に配置される値をユーザーが指定できるようにしました。14行目と16行目の間にこのような形の相互作用がありますが、テストする上では興味深いものの、これらのポイントは完全に必要というわけではありません。Chart Tradeはユーザーとの対話システムであることを忘れてはなりません。
14行目から16行目の代わりに、指標にデフォルト値を入力するだけです。これは20行目でおこなうことができます。ユーザーとの対話から得た値を使用する代わりに、呼び出しに直接値を入れることができます。このように、Chart Tradeはチャート上に指標が表示された後にユーザーが変更できるデフォルト値を持つことになります。
実際、この記事ではそのことは取り上げません。というのも、そのために少し変わったプロセスを使用するからです。デモビデオでわかるように、ユーザーから報告された値はChart Tradeに転送され、明確に表示されます。すでに述べたように、このような相互作用の存在はテスト目的には興味深いものです。
指標が通信を確立する能力があることは見ました。では、実際にオブジェクトを使わずに、ビデオのように指標に変更を反映させる方法を考えてみましょう。ビデオで見たように、グラフ上に存在する唯一のオブジェクトはOBJ_CHARTです。どうすればこんなことができるのか、何かアイデアはありますか。OBJ_CHARTだけでデータや値を変更するには?
何故このようなことが可能なのかわからない場合は、MetaTrader 5プラットフォームとMQL5言語が実際にどのように機能するのかを勉強する必要があります。説明を明確にするために、新しいトピックを立ち上げましょう。
オブジェクトと目標
プログラミングを学びたいと夢見る人のほとんどは、実際に自分が何をしているのかわかっていません。彼らの活動は、ある方法で物事を創造しようとすることから成っています。しかし、プログラミングとは適切な解決策を用意することではありません。
おそらく、これは完全には明確ではありません。さて、私の長年の様々な言語、プラットフォーム、システムでのプログラミングの経験を少しお伝えしようと思います。
どんなシステムであれ、それを使い始めるときに私たちが最初にすべきことは、そのシステムの能力を評価し、そのシステムが私たちに何を提供してくれるのかを理解することです。これは一般論です。つまり、なぜすべてがこのように創造され、そうでなかったのかを理解しようとしなければなりません。最も基本的な機能がどのように機能するかを理解したら、次に進み、より深く掘り下げることができます。
より深くというのは、これらの機能を向上させる方法を探すことでも、単にプログラミングをすることでもありません。その奥深さは、他がまだ探っていないリソースを利用しようとすることにあります。多くの人は、みんなが普段使用しているものだけを使用するように自分を制限しています。それは悪いことではありません。しかし、システムの能力を表面的にしか知らないで、どうやって改善策を提案できるでしょうか。このような考え方には意味がありません。作動している組立ラインを見ただけで、新しい生産方法を提案したがる子供のようなものです。この種のことに未来はなく、解決策よりも多くの問題を生み出す運命にあります。
おそらく、私はまだ十分に明確でないでしょう。MetaTrader 5を使用する場合、プラットフォームについて十分な知識を持ち、何が可能で何が不可能かを説明できると思っている人がいます。そして、彼らはMQL5に目を向け、いくつかの問題を解決しようとします。これは間違いです。MQL5を、他の言語と同じように、自分のニーズや願望を満たす魔法のような方法だと考えるべきではありません。MQL5は魔法の言語ではありません。この言語はMetaTrader 5の機能を拡張します。ただし、プラットフォームを意図されたものとは異なる形で機能させることはできません。
正しいアプローチは、MetaTrader 5がどのように機能するかを深く理解し、自分自身の市場の見方や分析方法に適合させる方法を探すことです。MetaTrader 5を探求するうちに、自分の市場観に合ったツールに変えるために何が必要なのかが見えてくるでしょう。これをおこなうには、MQL5を使用する必要があります。MQL5は、あなたや他のトレーダーの生活を容易にする方法でMetaTrader 5の扉を開きます。
このことを念頭に置いて、1つの疑問を考えることができます。多くのユーザーはMetaTrader 5の基本的な操作の詳細を知らないため、MetaTrader 5を過小評価しています。MetaTrader 5だけでなく、これらの詳細の1つは、テンプレートの概念です。シンプルで実用的な方法で、特定のものをカスタマイズし、調整し、整理することができます。注釈から、ある瞬間にある方法で市場を見るプロセスの簡素化までです。
テンプレートにはさまざまなものが含まれており、そのいくつかを調べる方法は以前紹介しました。「単一チャート上の複数インジケータ(第03部):カスタム定義の開発」では、図01に示すように、異なる指標を隣り合わせに配置できることを示しました。
図01:1つのサブウィンドウで複数の指標を使用する
上に示した概念は、テンプレートを使用して初めて可能になります。どんなに優れたプログラマーでMQL5に関する幅広い知識を持っていたとしても、MetaTrader 5の機能を理解しなければ、図01のような結果を得ることはできません。というのも、すべてがコードを書くことに帰結するわけではないからです。プログラミングは、他の方法では不可能な解決策を生み出す手助けをするだけです。しかし、何か新しいことが必要なときに最初に試すべきものではなく、望む結果を得るためのツールであるべきです。
私はなぜこんなことを言うのでしょうか。その理由は、冒頭のビデオ01にある通りです。いくらプログラミングができても、MQL5の仕組みを理解していても、MetaTrader 5の機能を理解していなければ、ビデオで紹介されているようなことはできません。
この話の重要な点は、私が「単一チャート上の複数インジケータ(第06部):MetaTrader 5をRADシステムに変える(II)」を発表したとき、1つのチャートに複数の指標を表示したことです。当時、私はあるMetaTrader 5の概念を使用していませんでした。それでも、いくつかのアイデアや概念に行き詰まっており、結局はふさわしくないことが判明しました。間違っていたとは言いません。適切ではなかったというだけです。もっといい解決策があります。これはまさに、その記事とその前の「単一チャート上の複数インジケータ(第05部):MetaTrader 5をRADシステムにする (I)」稿で示した内容によるものです。
どちらの場合も、テンプレートを開いて作業を試みました。しかし、この作業はすべて、表面を少しかじった程度のものでしかありません。目に見えるものの多くは、同じテンプレートの再プログラミングだからです。これは、MQL5でプログラミングすることで実装可能なRADシステムをエミュレートする方法でおこなわれました。
うまくはいきましたが、実際には、MetaTrader 5で作成されたテンプレートが、指標をチャートに配置する際に指標自体によって後で再作成されたことに気づくでしょう。その結果、テンプレートに存在していたすべてのオブジェクトが指標によって再作成されました。このようにして、MetaTrader 5はそこにあるオブジェクトにアクセスできるようになり、各オブジェクトに存在する値を設定変更できるようになりました。
しかし、時間が経つにつれて、このアイデアは改善できることが明らかになりました。そこで、最小限のオブジェクトしか使用しない、より適切なChart Tradeモデルを見つけました。さて、この記事で紹介すること以外にも、まだやるべきことがあります。しかし、ビデオ01を見ると、数値に変化があることがわかります。同時に、画面上には1つのオブジェクトしかありません。
これこそが、プログラミングが可能にすることなのです。これがなければ、MetaTrader 5で利用できるものに限られてしまいます。プログラミングを通じて、プラットフォームの機能を拡張します。これは、MetaTrader 5に既に存在するものを使用することで実現します。必要なものを正確に含むテンプレートを作成し、OBJ_CHARTに配置します。しかし、適切なプログラミングをしなければ、テンプレート内のオブジェクトに存在する値を変更することは不可能です。プログラミングを正しく使用することで、この問題を解決し、MetaTrader 5の機能を拡張します。
これを明確にするために、Chart Tradeで使用したテンプレートファイルを開いてください。以下にそのすべてを掲載します。
Chart Tradeファイル(テンプレート):
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>
その内容がまったく不必要に思えるかもしれないことは承知しています。添付ファイルにはファイルは含まれません。システム全体は、コードを対応するファイルに書き換えることでファイルを取得できるような方法で公開されます。これは、記事を読んで理解してもらうためです。ただ添付ファイルをダウンロードして、何も知らずにシステムを使用してほしくはありません。これによって記事が大幅に長くなったように見えるかもしれないが、実際はそうではなく、説明がより詳細になっただけです。
それでは、Chart Tradeのテンプレートファイルを詳しく見てみましょう。以下の行に注目してください。
descr=?
これはテンプレートファイルの何カ所かで、意図的におこなわれています。なぜでしょうか。descrはさまざまな場所に現れますが、上に示したように、これらの場所は主に107型のオブジェクトを指しています。107型のオブジェクトとは何でしょうか。
これらの型のオブジェクトの説明は、「単一チャート上の複数インジケータ(第05部):MetaTrader 5をRAD(I)システムに変える」稿で初めて登場しました。便宜上、この記事で紹介した表を以下に掲載します。
TYPE変数の値 | 参照されるオブジェクト |
---|---|
102 | OBJ_LABEL |
103 | OBJ_BUTTON |
106 | OBJ_BITMAP_LABEL |
107 | OBJ_EDIT |
110 | OBJ_RECTANGLE_LABEL |
つまり、オブジェクト107はOBJ_EDITです。これらは、ユーザーが何らかの情報を入力できるオブジェクトです。
しかし、テンプレートの中にあるオブジェクトに直接アクセスしたり、値を入力したりすることはできません。それは事実です。テンプレートに存在するオブジェクト107が指標から値を受け取ることができるように、この問題をどのように解決したのでしょうか。この質問に答えるには、テンプレートの使用を担当するクラスのコードを見る必要があります。
C_ChartFloatingRADクラスの更新
Chart Tradeにユーザーが入力した値を表示させるには、チャート上で指標を起動した直後にいくつかの基本的な操作をおこなう必要があります。これらの操作は、プログラミングを使用しなければ解決できないいくつかの問題を解決することを目的としています。このため、MetaTrader 5がどのように機能するかをよく理解することが非常に重要です。プラットフォームの動作原理を知らなければ、プログラミングなしでは解決できないこのような障害を克服するために必要なコードを作成することはできません。
C_ChartFloatingRADクラスの完全なコードを以下に示します。このコードは、現在の形では、ビデオ01に示されているように指標を動作させることができます。どうしてこうなるのか、お分かりになるでしょうか。
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. //+------------------------------------------------------------------+
C_ChartFloatingRADファイルには、前回の記事以降、ほとんど大きな追加がありません。これは意図的なものです。このファイルの最終版をお見せしても、なぜMetaTrader 5がテンプレートの値を変更することができるのかご理解いただけないでしょう。これは、CTRL+Bでオブジェクトリストウィンドウを開いたときに、リストにOBJ_CHARTだけが表示されるようにするためですが、値とウィンドウは変更されたままです。
では、なぜMetaTrader 5がテンプレートを通して何が起こっているかを知らせてくれるのか、その方法を理解しましょう。この点を忘れないでください:テンプレートの使用は止めず、OBJ_CHARTオブジェクトに適用します。これは94行目が実行され、95行目がMetaTrader 5にOBJ_CHARTを更新するように指示したときに起こります。この事実を考慮しなければ、コードにないものを探すのに長い時間を費やすことになります。例えば、実際にテンプレートファイルにあるものに対してです。
追加されたコードは38行目から123行目にかけて見ることができます。次回の記事でおこなうさらなるステップでは、多くの変更を必要としないように構成されています。これはとてもよいことです。この記事の説明に注意を払えば、次の説明は簡単に理解できるでしょう。プログラミングの観点から、次の記事で何がおこなわれるかを予測することもできるかもしれません。
クラスのコンストラクタから始めましょう。これにより、他の部分がはるかに理解しやすくなるからです。このコンストラクタは105行目から始まりますが、本当の変更は109行目から始まります。この行では、レバレッジの値が常に1以上であることを保証します。そのために三項演算子を使用します。特に複雑でも難しくもありません。
さて、110行目に移りましょう。この行は111行目と同様、Chart Tradeウィンドウに表示される値の調整をおこないます。この理由は、ユーザーがChart Trade指標が実行されているアセットに対して有効でない値を入力する可能性があるためです。たとえば、ドル先物の場合、変動は常にR$5.00から1契約あたりR$5.00の間になります。この場合、テイクプロフィットやストップロスを5の倍数でない値(例えばテイクプロフィット=R$76.00)で指定しても、この値に到達することはないので意味がありません。
つまり、110行目と111行目は2つの呼び出しをおこないます。1つ目は財務的価値をポイントに変換するもので、2つ目は逆にポイント価値を財務的価値に変換するものです。これで値が元の値に戻ったと思われるかもしれません。これは事実ですが、ここでは数値の変換と調整には数学的手法が使用されます。最初の呼び出しは、C_Terminalクラスにある関数を使用します。2つ目は、98行目の関数を実行します。
この98行目の関数は1行しか使用しません。100行目では実際に、指定されたpips数を金融価値に変換する計算を実行します。
これは簡単なことでした。では、現行システムの最も難しい部分を見てみましょう。
コンストラクタが113行目に達すると、非常に興味深いことが起こります。この113行目で一時ファイルの名前が作成されます。このファイルは一時的なものであることを忘れないでください。これは、MQL5\Filesで定義された領域に、この行113で特別に作成された他の情報とともに存在します。
113行目でファイル名を作成したら、114行目に進みます。この行では、テンプレートファイル(前のトピックで見ることができる)の内容を新しい名前で完全にコピーします。成功すれば、さらに続けます。しかし、コピーに失敗した場合は、そのことを呼び出し側に報告します。
本当の魔法は116行目と119行目の間に起こります。ここでは、Chart Trade指標がMetaTrader 5やユーザーから提供された値を受け取るようにします。これらの行は、クラスコードの60行目を呼び出します。これ以降は、コンストラクタの残りの部分については前回の記事で説明したので、この部分に取り組むことにします。しかし、最終的に60行目に進む前に、コードに追加されたもう1つの行、128行目に注目してください。コンストラクタで作成したファイルを削除します。作成されるファイルは一時的なものだと強調したのはこのためです。
60行目に進みましょう。ここで繰り返さなければならないことがあります(まだ基本的なことを説明している最中なので、ご辛抱ください)。最初のステップは、「オリジナル」ファイルを開くことです(「」で囲まれていることに注意)。これは66行目でおこないます。もし成功すれば、続行します。もし失敗すれば、呼び出し元に戻ります。
71行目では、一時ファイルから一時ファイルを作成します(奇妙に聞こえますが、他に言いようがありません)。失敗した場合は、開いているファイルを閉じて呼び出し元に戻ります。77行目までは、1つのファイルを開いて別のファイルを作るだけでした。実行が77行目に到達したら、ファイル全体をコピーするループに入ります。
待ってください。ファイル全体をコピーするですか。またですか。そうですが、今回は81行目で1つの条件をテストします。この条件は、テンプレートファイル内のオブジェクトがコピー処理中に見つかったかどうかです。そうなったら38行目に進み、そこで見つかったオブジェクトを処理します。いずれにせよ、分析対象のパターンが前のトピックのパターンであれば、38行目にジャンプします。独自のテンプレートを使用したい場合でも、オブジェクトに使用する名前を正しく定義している限り、使用することができます。
38行目で関数を呼び出した後、44行目まで実行します。ここでは、先ほどと同じようにファイルをコピーする作業を続けます。しかし、オブジェクトを閉じる行がまさにこの44行目に見つかると、呼び出し元のオブジェクト、つまり81行目に戻ります。ちょっと立ち止まって、38行目に出てくる関数を見てみましょう。
コピー中、46行目からソースファイルを読み込みます。その後、この行の内容を展開していきます。この分解を実行する47行目が、使用可能な命令が2つあると報告すれば、新しい実行スレッドが生成されます。そうでなければ、読まれた行が書き込まれます。これは56行目で起こります。
ここで、次の点に注意してください。47行目の分解中、変数i0の初期値は0です。これには特に注意してください。オブジェクト名が見つかると、i0変数に1が設定されます。ここに危険が潜んでいます。テンプレートファイルを手動で編集する場合は、オブジェクト名がパラメータの前に表示されるようにする必要があります。名前の前に指定できる唯一のパラメータは、オブジェクトのタイプです。名前の前に他のパラメータが来てはなりません。来れば、すべてのプロセスが失敗します。
50行目では、i0が目的のオブジェクトが見つかったことを示しているかどうかを確認します。この場合、この変数の値は1ですが、探しているパラメータに関する2つ目の条件があります。この場合、常にdescrを検索します。この2つの条件が成立すれば、コピー処理中に目的の値を書き込みます。このような修正は52行目でおこなわれます。その後、呼び出し元、つまり81行目に戻ります。
このプロセスがどのようにおこなわれるかを見てみましょう。特定の1行を除いて、ファイル全体をコピーします。変更されるのはこの行で、その結果、新しいデータがテンプレートに表示されたり、異なる外観になったりします。
ファイル全体のコピーと変更が終わったら、両方のファイルを閉じます。これは、83行目と84行目でおこなわれます。その後、85行目で一時ファイルの名前を、クラスが使用すると予想するファイルに変更しようとします。操作はビデオ01とまったく同じです。
結論
この資料では、テンプレートを管理できるようになるために必要な最初のステップを説明しました。そうすることで、私たちが必要としているものに適応することができます。これによって、かなり簡単なプログラミングでMetaTrader 5の機能をよりよく利用できるようになります。しかし、重要なことは、チャート上のオブジェクトの数を増やしたり減らしたりすることではありません。本当に重要なのは、MQL5によって、誰もがMetaTrader 5を自分のニーズに適したプラットフォームに変えることができるのであって、別の競合プラットフォームを作成するわけではないということを理解することです。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11664




- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索