English Русский Español Deutsch Português
preview
リプレイシステムの開発(第43回):Chart Traderプロジェクト(II)

リプレイシステムの開発(第43回):Chart Traderプロジェクト(II)

MetaTrader 5 | 16 8月 2024, 15:08
13 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第42回):Chart Traderプロジェクト(I)」では 、マウス指標と他の指標の相互作用をアレンジする方法を紹介しました。

Chart Trade指標がマウス指標と完璧に調和するようにコードを書き始めました。しかし、このChart Trade指標の最初のバージョンでおこなわれたこととは異なります。

ここでは、より高度で、それゆえに異なることをしますが、いずれにせよ、結果はビデオ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

図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

添付されたファイル |
Anexo.zip (420.65 KB)
GIT:それは何か? GIT:それは何か?
今回は、開発者にとって非常に重要なツールを紹介しましょう。GITに馴染みのない方は、この記事を読んでGITとは何か、MQL5でどのように使用するかをご覧ください。
知っておくべきMQL5ウィザードのテクニック(第24回):移動平均 知っておくべきMQL5ウィザードのテクニック(第24回):移動平均
移動平均は、ほとんどのトレーダーが使用し、理解している非常に一般的な指標です。この記事では、MQL5ウィザードで組み立てられたエキスパートアドバイザー(EA)の中で、あまり一般的ではないかもしれない使用例を探っていきます。
多通貨エキスパートアドバイザーの開発(第5回):可変ポジションサイズ 多通貨エキスパートアドバイザーの開発(第5回):可変ポジションサイズ
前回開発中のエキスパートアドバイザー(EA)は、固定されたポジションサイズのみを使用して取引をおこなうことができました。これはテスト用には許容できますが、実際の口座で取引する場合にはお勧めできません。可変のポジションサイズで取引できるようにしましょう。
リプレイシステムの開発(第42回):Chart Traderプロジェクト(I) リプレイシステムの開発(第42回):Chart Traderプロジェクト(I)
もっと面白いものを作りましょう。ネタバレはしたくないので、理解を深めるために記事を読んでください。リプレイ/シミュレーターシステムの開発に関する本連載の最初の段階から、私は、開発中のシステムと実際の市場の両方で同じようにMetaTrader 5プラットフォームを使用することがアイディアであると述べてきました。これが適切におこなわれることが重要です。ある道具を使用して訓練して戦い方を学んだ末、戦いの最中に別の道具を使用しなければならないというようなことは誰もしたくありません。