
リプレイシステムの開発(第47回):Chart Tradeプロジェクト(VI)
はじめに
前回の「リプレイシステムの開発(第46回):Chart Tradeプロジェクト(V)」では、データを個別に転送する必要がないように、実行ファイルにデータを追加する方法を示しました。この知識は近い将来におこなうことに非常に重要です。しかし、今のところは最初に実装する必要があるものの開発を続けます。
この記事では、Chart Trade指標を改良し、いくつかのEAで使用できるほど機能的にします。これにより、Chart Trade指標にアクセスし、実際にEAに接続されているかのように操作できるようになります。ただし、過去の「一からの取引エキスパートアドバイザーの開発(第30部):指標としてのCHART TRADE?」稿よりもはるかに興味深いものにしましょう。その記事では、Chart Tradeを条件指標として使用しました。今回は実際の指標になります。
これをおこなうには、他のタイプの指標を操作するときと同じように、非常に特殊な方法で機能させる必要があります。そのために、対応するデータバッファを作成します。このプロセスについては、以前にも別の記事で紹介しました。
これら3つの記事には、実際におこなうことの基礎が含まれています。まだ読んでいない場合は、ぜひ目を通してください。そうしないと、この記事を読む際に混乱し、基礎となる深い知識が不足するため理解が難しくなるリスクがあります。したがって、上記の記事を読んで内容をしっかり理解する必要があります。
変更を開始する前に、いくつかの小さな修正をおこなう必要があります。これらはすべて、必要なデータに簡単かつ適切にアクセスできるように、既存のC_ChartFloatingRADクラスコードに含まれています。そのため、Chart Trade指標の作業の最終段階に進むことができます。
小さな変化、大きな成果
おこなわれる変更は少なく、簡単です。もちろん、本連載を読んでいることが前提です。現在、リプレイ/シミュレーターシステムに関する記事の第2段階に入っています。以下は、Chart Trade指標の完全なコードです。クラスコードの説明を容易にするために、最初にこのコードを確認することが重要です。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Chart Trade base indicator." 04. #property description "This version communicates via buffer with the EA." 05. #property description "See the articles for more details." 06. #property version "1.47" 07. #property icon "/Images/Market Replay/Icons/Indicators.ico" 08. #property link "https://www.mql5.com/es/articles/11760" 09. #property indicator_chart_window 10. #property indicator_plots 0 11. #property indicator_buffers 1 12. //+------------------------------------------------------------------+ 13. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh> 14. //+------------------------------------------------------------------+ 15. C_ChartFloatingRAD *chart = NULL; 16. //+------------------------------------------------------------------+ 17. input int user01 = 1; //Leverage 18. input double user02 = 100.1; //Finance Take 19. input double user03 = 75.4; //Finance Stop 20. //+------------------------------------------------------------------+ 21. double m_Buff[]; 22. //+------------------------------------------------------------------+ 23. int OnInit() 24. { 25. bool bErr; 26. 27. chart = new C_ChartFloatingRAD("Indicator Chart Trade", new C_Mouse("Indicator Mouse Study"), user01, user02, user03); 28. 29. if (bErr = (_LastError != ERR_SUCCESS)) Print(__FILE__, " - [Error]: ", _LastError); 30. 31. SetIndexBuffer(0, m_Buff, INDICATOR_DATA); 32. ArrayInitialize(m_Buff, EMPTY_VALUE); 33. 34. return (bErr ? INIT_FAILED : INIT_SUCCEEDED); 35. } 36. //+------------------------------------------------------------------+ 37. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 38. { 39. (*chart).MountBuffer(m_Buff, rates_total); 40. 41. return rates_total; 42. } 43. //+------------------------------------------------------------------+ 44. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 45. { 46. (*chart).DispatchMessage(id, lparam, dparam, sparam); 47. (*chart).MountBuffer(m_Buff); 48. 49. ChartRedraw(); 50. } 51. //+------------------------------------------------------------------+ 52. void OnDeinit(const int reason) 53. { 54. if (reason == REASON_CHARTCHANGE) (*chart).SaveState(); 55. 56. delete chart; 57. } 58. //+------------------------------------------------------------------+
Chart Trade指標のソースコード
上記のコードには、Chart Trade指標が機能するために必要なすべての要素が含まれていることに注意してください。ただし、実用的な理由から、コードのほとんどは後で説明するクラスに移動されています。しかし、このコードはどのように機能するのでしょうか。EAにコマンドを送信して操作を実行するにはどうすればよいでしょうか。まず、指標コードで何が起こっているのかを理解しましょう。
11行目には、必要な最初のステージが含まれています。この行では、1つのバッファを使用することが定義されています。バッファはもっと多く使用することもできますが、1つで十分です。
使用するバッファは21行目で宣言されています。ただし、その使用方法は31行目でのみ定義されます。バッファが「ゴミ」で埋め尽くされることは望ましくないため、32行目でバッファを初期化し、ゼロ値のみが含まれるようにします。
ご覧のとおり、指標コードは以前の記事と比べて大きな変更はありません。ただし、39行目と47行目の2つの新しい行が追加されました。どちらの行も、クラス内の同じ関数を呼び出しています。これについては後ほど説明します。数とパラメーターが異なるため、これらは異なる関数であると思われるかもしれません。しかし、すぐに、どちらも同じであることに気付くでしょう。これを理解するために、以下に示すクラスの完全なコードを見てみましょう。
001.//+------------------------------------------------------------------+ 002.#property copyright "Daniel Jose" 003.//+------------------------------------------------------------------+ 004.#include "../Auxiliar/C_Mouse.mqh" 005.#include "../Auxiliar/Interprocess.mqh" 006.#include "C_AdjustTemplate.mqh" 007.//+------------------------------------------------------------------+ 008.#define macro_NameGlobalVariable(A) StringFormat("ChartTrade_%u%s", GetInfoTerminal().ID, A) 009.//+------------------------------------------------------------------+ 010.class C_ChartFloatingRAD : private C_Terminal 011.{ 012. public : 013. enum eObjectsIDE {MSG_LEVERAGE_VALUE, MSG_TAKE_VALUE, MSG_STOP_VALUE, MSG_MAX_MIN, MSG_TITLE_IDE, MSG_DAY_TRADE, MSG_BUY_MARKET, MSG_SELL_MARKET, MSG_CLOSE_POSITION, MSG_NULL}; 014. struct stData 015. { 016. int Leverage; 017. double PointsTake, 018. PointsStop; 019. bool IsDayTrade; 020. union u01 021. { 022. ulong TickCount; 023. double dValue; 024. }uCount; 025. eObjectsIDE Msg; 026. }; 027. private : 028. struct st00 029. { 030. int x, y, minx, miny; 031. string szObj_Chart, 032. szObj_Editable, 033. szFileNameTemplate; 034. long WinHandle; 035. double FinanceTake, 036. FinanceStop; 037. bool IsMaximized; 038. stData ConfigChartTrade; 039. struct st01 040. { 041. int x, y, w, h; 042. color bgcolor; 043. int FontSize; 044. string FontName; 045. }Regions[MSG_NULL]; 046. }m_Info; 047.//+------------------------------------------------------------------+ 048. C_Mouse *m_Mouse; 049. string m_szShortName; 050.//+------------------------------------------------------------------+ 051. void CreateWindowRAD(int w, int h) 052. { 053. m_Info.szObj_Chart = "Chart Trade IDE"; 054. m_Info.szObj_Editable = m_Info.szObj_Chart + " > Edit"; 055. ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0); 056. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x); 057. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y); 058. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w); 059. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h); 060. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false); 061. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false); 062. m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID); 063. }; 064.//+------------------------------------------------------------------+ 065. void AdjustEditabled(C_AdjustTemplate &Template, bool bArg) 066. { 067. for (eObjectsIDE c0 = 0; c0 <= MSG_STOP_VALUE; c0++) 068. if (bArg) 069. { 070. Template.Add(EnumToString(c0), "bgcolor", NULL); 071. Template.Add(EnumToString(c0), "fontsz", NULL); 072. Template.Add(EnumToString(c0), "fontnm", NULL); 073. } 074. else 075. { 076. m_Info.Regions[c0].bgcolor = (color) StringToInteger(Template.Get(EnumToString(c0), "bgcolor")); 077. m_Info.Regions[c0].FontSize = (int) StringToInteger(Template.Get(EnumToString(c0), "fontsz")); 078. m_Info.Regions[c0].FontName = Template.Get(EnumToString(c0), "fontnm"); 079. } 080. } 081.//+------------------------------------------------------------------+ 082.inline void AdjustTemplate(const bool bFirst = false) 083. { 084.#define macro_AddAdjust(A) { \ 085. (*Template).Add(A, "size_x", NULL); \ 086. (*Template).Add(A, "size_y", NULL); \ 087. (*Template).Add(A, "pos_x", NULL); \ 088. (*Template).Add(A, "pos_y", NULL); \ 089. } 090.#define macro_GetAdjust(A) { \ 091. m_Info.Regions[A].x = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_x")); \ 092. m_Info.Regions[A].y = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_y")); \ 093. m_Info.Regions[A].w = (int) StringToInteger((*Template).Get(EnumToString(A), "size_x")); \ 094. m_Info.Regions[A].h = (int) StringToInteger((*Template).Get(EnumToString(A), "size_y")); \ 095. } 096.#define macro_PointsToFinance(A) A * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.ConfigChartTrade.Leverage - 1))) * GetInfoTerminal().AdjustToTrade 097. 098. C_AdjustTemplate *Template; 099. 100. if (bFirst) 101. { 102. Template = new C_AdjustTemplate(m_Info.szFileNameTemplate = IntegerToString(GetInfoTerminal().ID) + ".tpl", true); 103. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_AddAdjust(EnumToString(c0)); 104. AdjustEditabled(Template, true); 105. }else Template = new C_AdjustTemplate(m_Info.szFileNameTemplate); 106. m_Info.ConfigChartTrade.Leverage = (m_Info.ConfigChartTrade.Leverage <= 0 ? 1 : m_Info.ConfigChartTrade.Leverage); 107. m_Info.FinanceTake = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceTake), m_Info.ConfigChartTrade.Leverage)); 108. m_Info.FinanceStop = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceStop), m_Info.ConfigChartTrade.Leverage)); 109. m_Info.ConfigChartTrade.PointsTake = FinanceToPoints(m_Info.FinanceTake, m_Info.ConfigChartTrade.Leverage); 110. m_Info.ConfigChartTrade.PointsStop = FinanceToPoints(m_Info.FinanceStop, m_Info.ConfigChartTrade.Leverage); 111. (*Template).Add("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol); 112. (*Template).Add("MSG_LEVERAGE_VALUE", "descr", IntegerToString(m_Info.ConfigChartTrade.Leverage)); 113. (*Template).Add("MSG_TAKE_VALUE", "descr", DoubleToString(m_Info.FinanceTake, 2)); 114. (*Template).Add("MSG_STOP_VALUE", "descr", DoubleToString(m_Info.FinanceStop, 2)); 115. (*Template).Add("MSG_DAY_TRADE", "state", (m_Info.ConfigChartTrade.IsDayTrade ? "1" : "0")); 116. (*Template).Add("MSG_MAX_MIN", "state", (m_Info.IsMaximized ? "1" : "0")); 117. (*Template).Execute(); 118. if (bFirst) 119. { 120. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_GetAdjust(c0); 121. m_Info.Regions[MSG_TITLE_IDE].w = m_Info.Regions[MSG_MAX_MIN].x; 122. AdjustEditabled(Template, false); 123. }; 124. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, (m_Info.IsMaximized ? 210 : m_Info.Regions[MSG_TITLE_IDE].h + 6)); 125. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, (m_Info.IsMaximized ? m_Info.x : m_Info.minx)); 126. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, (m_Info.IsMaximized ? m_Info.y : m_Info.miny)); 127. 128. delete Template; 129. 130. ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate); 131. ChartRedraw(m_Info.WinHandle); 132. 133.#undef macro_PointsToFinance 134.#undef macro_GetAdjust 135.#undef macro_AddAdjust 136. } 137.//+------------------------------------------------------------------+ 138. eObjectsIDE CheckMousePosition(const int x, const int y) 139. { 140. int xi, yi, xf, yf; 141. 142. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) 143. { 144. xi = (m_Info.IsMaximized ? m_Info.x : m_Info.minx) + m_Info.Regions[c0].x; 145. yi = (m_Info.IsMaximized ? m_Info.y : m_Info.miny) + m_Info.Regions[c0].y; 146. xf = xi + m_Info.Regions[c0].w; 147. yf = yi + m_Info.Regions[c0].h; 148. if ((x > xi) && (y > yi) && (x < xf) && (y < yf)) return c0; 149. } 150. return MSG_NULL; 151. } 152.//+------------------------------------------------------------------+ 153.inline void DeleteObjectEdit(void) 154. { 155. ChartRedraw(); 156. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Editable); 157. m_Info.ConfigChartTrade.Msg = MSG_NULL; 158. } 159.//+------------------------------------------------------------------+ 160. template <typename T > 161. void CreateObjectEditable(eObjectsIDE arg, T value) 162. { 163. long id = GetInfoTerminal().ID; 164. 165. DeleteObjectEdit(); 166. CreateObjectGraphics(m_Info.szObj_Editable, OBJ_EDIT, clrBlack, 0); 167. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XDISTANCE, m_Info.Regions[arg].x + m_Info.x + 3); 168. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YDISTANCE, m_Info.Regions[arg].y + m_Info.y + 3); 169. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XSIZE, m_Info.Regions[arg].w); 170. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YSIZE, m_Info.Regions[arg].h); 171. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_BGCOLOR, m_Info.Regions[arg].bgcolor); 172. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_ALIGN, ALIGN_CENTER); 173. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_FONTSIZE, m_Info.Regions[arg].FontSize - 1); 174. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_FONT, m_Info.Regions[arg].FontName); 175. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_TEXT, (typename(T) == "double" ? DoubleToString(value, 2) : (string) value)); 176. ChartRedraw(); 177. m_Info.ConfigChartTrade.Msg = MSG_NULL; 178. } 179.//+------------------------------------------------------------------+ 180. bool RestoreState(void) 181. { 182. uCast_Double info; 183. bool bRet; 184. 185. if (bRet = GlobalVariableGet(macro_NameGlobalVariable("P"), info.dValue)) 186. { 187. m_Info.x = info._int[0]; 188. m_Info.y = info._int[1]; 189. } 190. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("M"), info.dValue) : bRet)) 191. { 192. m_Info.minx = info._int[0]; 193. m_Info.miny = info._int[1]; 194. } 195. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("B"), info.dValue) : bRet)) 196. { 197. m_Info.ConfigChartTrade.IsDayTrade = info._char[0]; 198. m_Info.IsMaximized = info._char[1]; 199. m_Info.ConfigChartTrade.Msg = (eObjectsIDE)info._char[2]; 200. } 201. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("L"), info.dValue) : bRet)) 202. m_Info.ConfigChartTrade.Leverage = info._int[0]; 203. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("Y"), m_Info.ConfigChartTrade.uCount.dValue) : bRet); 204. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("T"), m_Info.FinanceTake) : bRet); 205. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("S"), m_Info.FinanceStop) : bRet); 206. 207. 208. GlobalVariablesDeleteAll(macro_NameGlobalVariable("")); 209. 210. return bRet; 211. } 212.//+------------------------------------------------------------------+ 213. public : 214.//+------------------------------------------------------------------+ 215. C_ChartFloatingRAD(const string szShortName) 216. :m_Mouse(NULL), 217. m_szShortName(szShortName) 218. { 219. } 220.//+------------------------------------------------------------------+ 221. C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const int Leverage, const double FinanceTake, const double FinanceStop) 222. :C_Terminal(), 223. m_szShortName(NULL) 224. { 225. if (!IndicatorCheckPass(szShortName)) SetUserError(C_Terminal::ERR_Unknown); 226. m_Mouse = MousePtr; 227. if (!RestoreState()) 228. { 229. m_Info.ConfigChartTrade.Leverage = Leverage; 230. m_Info.FinanceTake = FinanceTake; 231. m_Info.FinanceStop = FinanceStop; 232. m_Info.ConfigChartTrade.IsDayTrade = true; 233. m_Info.ConfigChartTrade.uCount.TickCount = 0; 234. m_Info.ConfigChartTrade.Msg = MSG_NULL; 235. m_Info.IsMaximized = true; 236. m_Info.minx = m_Info.x = 115; 237. m_Info.miny = m_Info.y = 64; 238. } 239. CreateWindowRAD(170, 210); 240. AdjustTemplate(true); 241. } 242.//+------------------------------------------------------------------+ 243. ~C_ChartFloatingRAD() 244. { 245. if (m_Mouse == NULL) return; 246. ChartRedraw(); 247. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Chart); 248. FileDelete(m_Info.szFileNameTemplate); 249. 250. delete m_Mouse; 251. } 252.//+------------------------------------------------------------------+ 253. void SaveState(void) 254. { 255.#define macro_GlobalVariable(A, B) if (GlobalVariableTemp(A)) GlobalVariableSet(A, B); 256. 257. uCast_Double info; 258. 259. if (m_Mouse == NULL) return; 260. info._int[0] = m_Info.x; 261. info._int[1] = m_Info.y; 262. macro_GlobalVariable(macro_NameGlobalVariable("P"), info.dValue); 263. info._int[0] = m_Info.minx; 264. info._int[1] = m_Info.miny; 265. macro_GlobalVariable(macro_NameGlobalVariable("M"), info.dValue); 266. info._char[0] = m_Info.ConfigChartTrade.IsDayTrade; 267. info._char[1] = m_Info.IsMaximized; 268. info._char[2] = (char)m_Info.ConfigChartTrade.Msg; 269. macro_GlobalVariable(macro_NameGlobalVariable("B"), info.dValue); 270. info._int[0] = m_Info.ConfigChartTrade.Leverage; 271. macro_GlobalVariable(macro_NameGlobalVariable("L"), info.dValue); 272. macro_GlobalVariable(macro_NameGlobalVariable("T"), m_Info.FinanceTake); 273. macro_GlobalVariable(macro_NameGlobalVariable("S"), m_Info.FinanceStop); 274. macro_GlobalVariable(macro_NameGlobalVariable("Y"), m_Info.ConfigChartTrade.uCount.dValue); 275. 276.#undef macro_GlobalVariable 277. } 278.//+------------------------------------------------------------------+ 279.inline void MountBuffer(double &Buff[], const int iPos = -1) 280. { 281. static int posBuff = 0; 282. uCast_Double info; 283. 284. if ((m_szShortName != NULL) || (m_Info.ConfigChartTrade.Msg == MSG_NULL)) return; 285. posBuff = (iPos > 5 ? iPos - 5 : posBuff); 286. Buff[posBuff + 0] = m_Info.ConfigChartTrade.uCount.dValue; 287. info._char[0] = (char)m_Info.ConfigChartTrade.IsDayTrade; 288. info._char[1] = (char)m_Info.ConfigChartTrade.Msg; 289. Buff[posBuff + 1] = info.dValue; 290. info._int[0] = m_Info.ConfigChartTrade.Leverage; 291. Buff[posBuff + 2] = info.dValue; 292. Buff[posBuff + 3] = m_Info.ConfigChartTrade.PointsTake; 293. Buff[posBuff + 4] = m_Info.ConfigChartTrade.PointsStop; 294. } 295.//+------------------------------------------------------------------+ 296.inline const stData GetDataBuffer(void) 297. { 298. double Buff[]; 299. int handle; 300. uCast_Double info; 301. stData data; 302. 303. ZeroMemory(data); 304. if (m_szShortName == NULL) return data; 305. if ((handle = ChartIndicatorGet(ChartID(), 0, m_szShortName)) == INVALID_HANDLE) return data; 306. if (CopyBuffer(handle, 0, 0, 5, Buff) == 5) 307. { 308. data.uCount.dValue = Buff[0]; 309. info.dValue = Buff[1]; 310. data.IsDayTrade = (bool)info._char[0]; 311. data.Msg = (C_ChartFloatingRAD::eObjectsIDE) info._char[1]; 312. info.dValue = Buff[2]; 313. data.Leverage = info._int[0]; 314. data.PointsTake = Buff[3]; 315. data.PointsStop = Buff[4]; 316. } 317. if (handle != INVALID_HANDLE) IndicatorRelease(handle); 318. 319. return data; 320. }; 321.//+------------------------------------------------------------------+ 322. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 323. { 324.#define macro_AdjustMinX(A, B) { \ 325. B = (A + m_Info.Regions[MSG_TITLE_IDE].w) > x; \ 326. mx = x - m_Info.Regions[MSG_TITLE_IDE].w; \ 327. A = (B ? (mx > 0 ? mx : 0) : A); \ 328. } 329.#define macro_AdjustMinY(A, B) { \ 330. B = (A + m_Info.Regions[MSG_TITLE_IDE].h) > y; \ 331. my = y - m_Info.Regions[MSG_TITLE_IDE].h; \ 332. A = (B ? (my > 0 ? my : 0) : A); \ 333. } 334. 335. static int sx = -1, sy = -1; 336. int x, y, mx, my; 337. static eObjectsIDE obj = MSG_NULL; 338. double dvalue; 339. bool b1, b2, b3, b4; 340. eObjectsIDE tmp; 341. 342. if (m_szShortName == NULL) switch (id) 343. { 344. case CHARTEVENT_CHART_CHANGE: 345. x = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_WIDTH_IN_PIXELS); 346. y = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_HEIGHT_IN_PIXELS); 347. macro_AdjustMinX(m_Info.x, b1); 348. macro_AdjustMinY(m_Info.y, b2); 349. macro_AdjustMinX(m_Info.minx, b3); 350. macro_AdjustMinY(m_Info.miny, b4); 351. if (b1 || b2 || b3 || b4) AdjustTemplate(); 352. break; 353. case CHARTEVENT_MOUSE_MOVE: 354. if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) switch (tmp = CheckMousePosition(x = (int)lparam, y = (int)dparam)) 355. { 356. case MSG_TITLE_IDE: 357. if (sx < 0) 358. { 359. DeleteObjectEdit(); 360. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false); 361. sx = x - (m_Info.IsMaximized ? m_Info.x : m_Info.minx); 362. sy = y - (m_Info.IsMaximized ? m_Info.y : m_Info.miny); 363. } 364. if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, mx); 365. if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, my); 366. if (m_Info.IsMaximized) 367. { 368. m_Info.x = (mx > 0 ? mx : m_Info.x); 369. m_Info.y = (my > 0 ? my : m_Info.y); 370. }else 371. { 372. m_Info.minx = (mx > 0 ? mx : m_Info.minx); 373. m_Info.miny = (my > 0 ? my : m_Info.miny); 374. } 375. break; 376. case MSG_BUY_MARKET: 377. case MSG_SELL_MARKET: 378. case MSG_CLOSE_POSITION: 379. DeleteObjectEdit(); 380. m_Info.ConfigChartTrade.Msg = tmp; 381. m_Info.ConfigChartTrade.uCount.TickCount = GetTickCount64(); 382. break; 383. }else if (sx > 0) 384. { 385. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true); 386. sx = sy = -1; 387. } 388. break; 389. case CHARTEVENT_OBJECT_ENDEDIT: 390. switch (obj) 391. { 392. case MSG_LEVERAGE_VALUE: 393. case MSG_TAKE_VALUE: 394. case MSG_STOP_VALUE: 395. dvalue = StringToDouble(ObjectGetString(GetInfoTerminal().ID, m_Info.szObj_Editable, OBJPROP_TEXT)); 396. if (obj == MSG_TAKE_VALUE) 397. m_Info.FinanceTake = (dvalue <= 0 ? m_Info.FinanceTake : dvalue); 398. else if (obj == MSG_STOP_VALUE) 399. m_Info.FinanceStop = (dvalue <= 0 ? m_Info.FinanceStop : dvalue); 400. else 401. m_Info.ConfigChartTrade.Leverage = (dvalue <= 0 ? m_Info.ConfigChartTrade.Leverage : (int)MathFloor(dvalue)); 402. AdjustTemplate(); 403. obj = MSG_NULL; 404. ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable); 405. break; 406. } 407. break; 408. case CHARTEVENT_OBJECT_CLICK: 409. if (sparam == m_Info.szObj_Chart) switch (obj = CheckMousePosition(x = (int)lparam, y = (int)dparam)) 410. { 411. case MSG_DAY_TRADE: 412. m_Info.ConfigChartTrade.IsDayTrade = (m_Info.ConfigChartTrade.IsDayTrade ? false : true); 413. DeleteObjectEdit(); 414. break; 415. case MSG_MAX_MIN: 416. m_Info.IsMaximized = (m_Info.IsMaximized ? false : true); 417. DeleteObjectEdit(); 418. break; 419. case MSG_LEVERAGE_VALUE: 420. CreateObjectEditable(obj, m_Info.ConfigChartTrade.Leverage); 421. break; 422. case MSG_TAKE_VALUE: 423. CreateObjectEditable(obj, m_Info.FinanceTake); 424. break; 425. case MSG_STOP_VALUE: 426. CreateObjectEditable(obj, m_Info.FinanceStop); 427. break; 428. } 429. if (obj != MSG_NULL) AdjustTemplate(); 430. break; 431. } 432. } 433.//+------------------------------------------------------------------+ 434.}; 435.//+------------------------------------------------------------------+ 436.#undef macro_NameGlobalVariable 437.//+------------------------------------------------------------------+
C_ChartFloatingRADクラスのソースコード
記事中でソースコードを公開するのは冗談のように思えるかもしれませんが、冗談ではありません。実際には、何が起こっているのかをできるだけ詳しく説明したいのです。これは、読者がこのコードを実際に使用できるようにするためではなく、理解してより良いものを作成できるようにするためです。
では、ここで何が起こっているのかを理解してみましょう。このクラスの仕組みを理解しなければ、次に開発されるものを理解することはできません。
冒頭にいくつかの変更があります。12行目にpublic句を宣言します。これを使用して、クラス外からデータにアクセスできるようにします。同じデータを他の場所に配置できると思われるかもしれません。ここでは、構造体と列挙体を1つずつ宣言します。列挙体はすでにおなじみですが、構造体は新しいものです。14行目と26行目の間には、必要なデータを整理するために使用される構造体の宣言があります。
この構造体のほとんどはかなり理解しやすく、説明もほとんど必要ありません。しかし、ここには奇妙に見えるものがいくつかあります。20行目と24行目の間のunionの目的は何でしょうか。また、25行目の目的は何でしょうか。unionにより、より簡単に転送できるようになります。また、25行目は非常に特定の瞬間に使用されます。これについては後で説明します。
同じ構造体が38行目にも記載されています。覚えておいてください。クラス内に存在するデータは、クラス外から直接アクセスすることはできません。そのため、そのようなデータにアクセスする手段が必要です。実際には直接アクセスすることはありません。指標のソースコードからわかるように、そのようなアクセスはありません。次は49行目で、興味深い処理がおこなわれます。これは一種のセレクターとして機能しますが、これは後で明らかになります。
106行目では、38行目の構造体で宣言された最初の変数を収集して適応します。これは基本的に以前と同じことですが、ここでは少し異なるモデルを使用していることに注意してください。
109行目で変数の1つを調整します。これは、テイクプロフィット値のポイント数の変数です。この点に注意してください。私は財務値ではなく、ポイント数で話しています。これら2つを混同しないでください。また、現在の取引価格に基づくポイント数についても言及していません。一般的なポイントについて話しているのです。価格は重要ではなく、シフトポイントがいくつあるかが重要です。また、このポイント値は財務的に調整されることにも注意してください。この調整は107行目でおこなわれます。
110行目にも同様のことが書かれていますが、今回はストップロス値に対しておこなっています。109行目のポイントを考慮する前に、107行目で財務値を調整したのと同じです。108行目では、ストップロスポイントを考慮する前にストップ財務を調整しています。この時点で何が起こっているのかを理解することが非常に重要です。これが理解できないと、後で注文を出すときにおこなわれる調整を理解するのが難しくなります。
作業を少しでも楽にするために、添付ファイルにはマウス指標とChart Trade指標、さらに何が起こっているかを理解できる非常にシンプルなエキスパートアドバイザー(EA)が含まれています。セキュリティ上の理由から、添付ファイルのEAは注文をおこなわず、入力された値を出力するだけです。これにより、システムが実際にどのように機能するのかを理解することができます。
157行目と177行目では、実用的な理由から、もう1つの変数の値を調整します。今のところ、アクセスはおこなわれていません。変数の値を設定および調整するだけです。しかし、203行目を見ると、何かがおかしいようです。なぜこの値をグローバル端末変数に保存するのでしょうか。本当にこれをおこなう必要があるのでしょうか、それとも時間の無駄になるのでしょうか。実際、これをおこなう必要があります。その理由は、Chart Trade指標を削除してチャートに再ロードすると、メモリ内のすべての値が失われるということです。しかし、この値は私たちにとって非常に重要です。
ここで、以前保存した値を復元します。つまり、203行目で復元したこの同じ値は、実際には274行目に保存されたものです。この説明ではいくつかの関数を省略していることに気付いたかもしれません。それでは、それらについて見ていきましょう。まずはコンストラクタから始めましょう。そうです、クラスコンストラクタは1つではなく2つあります。その理由は、マウス指標について説明した以前の記事と同じです。バッファからデータを転送するメソッドが必要です。
正直に言うと、実際には必要ありません。EAまたは指標で直接これをおこなうことができます。ただし、利便性のために、私はすべてを1つにまとめることを好みます。この方法では、後で変更が必要になった場合、C_ChartFloatingRADクラスを変更するだけで済みます。モジュールの標準化を実現するために各プログラムを個別に構成する必要はありません。コンストラクタに戻ると、221行目から始まる古いコンストラクタがあります。基本的に、指標名を初期化する223行目からデータを取得します。注:注:この名前は、バッファへの書き込みではなく、バッファからの読み取りに使用されます。さらに、232行目から234行目に新しい変数を導入します。すべてではなく、残りはテンプレート設定手順に従って構成されます。
2番目のコンストラクタは非常にシンプルで、215行目から始まります。ここでは、主にデフォルト値を割り当てます。これは、変換フェーズで発生します。マウス指標と同様に、ここでも2つのフェーズがあります。1つはデータをバッファに書き込むフェーズ、もう1つはバッファを読み取るフェーズです。ただし、これはプログラミングが間違っているためではありません。ここで何か間違っていると感じた場合は、私たちが何をしているのか理解していない可能性があります。実際、指標を使用するとき、データをバッファに書き込みます。このデータは、通常はEAなどの他のプログラムによってCopyBuffer経由で読み取られます。これが2つのフェーズがある理由であり、2つのコンストラクタがある理由です。
コンストラクタとは異なり、デストラクタは1つしか持てず、243行目から始まります。ここで追加したのは245行目だけです。このクラスを指標で使用する場合、デストラクタが呼び出されると、245行目のチェックが成功し、作成されたオブジェクトを削除できます。ただし、このクラスを使用して指標バッファを読み取ると、245行目のテストが失敗し、オブジェクトが削除されなくなります。シンプルですが機能的なメカニズムです。
ここまでは簡単な部分でした。次は、説明の重要な部分です。やり取りがどのようにおこなわれ、データがバッファに保存され、バッファから読み取られる方法を見てみましょう。この部分は、初心者にとっては少しわかりにくいかもしれません。そのため、以前の記事で説明した概念を理解することが非常に重要です。少し簡単にするために、図01を見てみましょう。
図01:相互作用図
図01では、指標からEAに情報を送信するための通信システムを示しています。バッファは実際には指標の一部ではないことに注意してください。バッファは指標で宣言されていますが、指標のメモリの一部とは見なされません。実際、MetaTrader 5ではサポートされており、チャートから指標を削除すると、バッファに使用されていたメモリが解放されます。しかし、ここに危険の1つがあります。データは実際には破壊されず、メモリが解放されるだけです。これの完全な危険性は何でしょうか。簡単な言葉で説明してみます。
指標がチャートから削除されたためにMetaTrader 5でバッファが配置されていたメモリが解放された場合、これはバッファへの書き込み後に発生する可能性があります。指標がチャートに戻された場合、バッファにまだデータが含まれている可能性があります。これは最新のアップデートで発生する可能性があります。したがって、EAがCopyBufferを使用してこのデータを読み取ると、誤って読み取られる可能性があります。
この問題は非常に深刻なので、バッファにアクセスするときは細心の注意を払う必要があります。書き込みと読み取りの同期を実現するには、C_ChartFloatingRADクラスのDispatchMessageメソッドを変更する必要があります。バッファへの書き込みと読み取りの同期は非常に重要です。正しくおこなわれないと、ユーザーが実行するために送信したものと実際に実行されるものの間に遅延が生じます。つまり、ユーザーが買い注文を送信しても、実行されません。ただし、その直後に売り注文を送信すると、買いが実行されます。この種の障害は、MetaTrader 5プラットフォームが原因ではなく、適切なイベント同期を確保するためのコードの書き方に関する誤解が原因です。
実際、EAとChart Trade指標の間にはコード上のつながりはありません。この通信は、バッファを使用して実装されます。したがって、EAはChart Tradeが何をしているかを知りません。同様に、Chart TradeもEAが実際に何をしているかを知りません。ただし、MetaTrader 5は両方が何をしているかを知っています。指標とEAの共通点はMetaTrader 5であるため、これを使用して物事を実現します。EAとChart Trade指標が同じプログラムであるという印象を読者やユーザーが得るのは、魔法のようなものです。
同じくらい重要な点がもう1つあります。以前の記事で説明したマウス指標がないと、Chart Trade指標は機能しないことを知っておく必要があります。チャートには、マウス指標、Chart Trade指標、EA、および今後説明するその他の3つのアプリケーションがすべて必要です。これがないと、システム全体がまったく機能しません。
これらすべてはどのように機能するのでしょうか。これらはすべて、C_ChartFloatingRADクラスの353行目にあるCHARTEVENT_MOUSE_MOVEイベントによって保証されています。マウス指標がチャート上にない場合は、Chart Tradeの値をクリックして編集および変更できます。これは、このようなイベントが必ずしもマウス指標に関連しているわけではないためです。ただし、マウス指標がチャート上に配置されていない限り、買い、売り、クローズ注文を送信したり、Chart Trade指標を移動したりすることはできません。
でもちょっと待ってください。Chart Tradeとやり取りするには、マウス指標をチャート上に配置する必要がありますか。はい。この依存関係を削除することは可能ですが、私が説明する他の方法を使用する場合は、後で別の問題が発生します。これらは、私のように作業したい場合に耐えなければならないコストです。これが、システムの仕組みをよく理解することが重要であり、そうしないと、信頼できないシステムになってしまいます。
しかし、システムをどのように同期したかを理解するために、コードに戻りましょう。これを完全に理解するには、指標のソースコードが何をおこなうかを理解する必要がありますが、この記事の冒頭でリンクした記事を読んでいれば、問題なく理解できるはずです。したがって、指標コードがどのように機能するかをすでに理解していると仮定しましょう。これにより、クラスコードに集中できます。
マウスをクリックまたは動かすたびに、MetaTrader 5はイベントを生成します。クリックイベントは通常、CHARTEVENT_OBJECT_CLICKを使用して処理されます。ただし、このハンドラを使用すると、同期を維持できません。その理由は説明するのが非常に複雑で、操作が実行される順序に関係しています。したがって、3つのChart Tradeボタン(買いボタン、売りボタン、ポジションクローズボタン)のいずれかがクリックされたときに同時にEAでイベントが生成されるようにするには、少し異なる方法を実行します。
そのため、DispatchMessageメソッドにあるこのコードを前回の記事の同じコードと比較すると、わずかに異なることがわかります。違いは、前述のボタンのクリックが処理される方法にあります。以前のバージョンでは、このクリックはCHARTEVENT_OBJECT_CLICKイベントで処理されていましたが、現在はCHARTEVENT_MOUSE_MOVE で処理されています。コード自体がどのオブジェクトがクリックされたかを示しているため、整理しやすくするために新しい変数を作成しました。この変数は340行目で宣言され、その値は354行目で設定されています。
これから説明する内容に注意してください。376行目から378行目にかけてボタンコードを配置します。マウス指標がデータを送信すると、EAに実行コマンドを送信できます。ただし、ここで1つ小さな詳細があります。どのボタンが押されたかをEAに通知するにはどうすればよいでしょうか。これは非常に簡単です。ボタンコードをEAに送信します。これは380行目でおこなわれます。次に、381行目で、一意の番号を生成するためにティック数を記録します。これはEAに必要になります。これがどのように機能するかはすぐに理解できます。
したがって、生成された各イベントに対して、バッファに送信するデータを準備するDispatchMessage関数の呼び出しに加えて、別の呼び出しがおこなわれます。これは、実際にデータをバッファに配置するものです。そのコードは、クラスの279行目から始まっています。次に、静的変数がある281行目を見てみましょう。これは、OnCalculateイベントによって渡された値を保存します。つまり、rates_total値を保存する必要があります。その理由は、すでに前に説明しました。理由を理解するには、冒頭にリストされている記事を読んでください。このようにして、OnChartEventハンドラが呼び出されたときに、バッファ内のデータを配置する場所がわかります。
284行目で、Chart Trade指標のみがメモリにデータを書き込むことを確認するチェックを実行していることに注目してください。さらに、メモリへの記録は、必要なボタンの1つが押されたときにのみおこなわれます。これはすべて非常に良いことです。ただし、EAがChart Trade指標から送信されたデータを解釈できない場合、これは何の価値もありません。EAがデータをどのように解釈できるかを理解するには、できるだけ基本的な他のコードを検討する必要があります。
テストEAの使用
すべてをテストする必要があるため、テストが適切におこなわれ、実際に何が起こっているかを明確に示す必要があります。この場合、Chart Trade指標、マウス指標、EA間の相互作用をテストするには、非常にシンプルなシステムを使用する必要があります。ただし、同時に、このシステムはシンプルであるだけでなく、将来実際に使用できる方法で機能する必要があります。
この基準に基づき、以下のコードを使用します。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Demo version between interaction of Chart Trade and EA" 04. #property version "1.47" 05. #property link "https://www.mql5.com/es/articles/11760" 06. //+------------------------------------------------------------------+ 07. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh> 08. //+------------------------------------------------------------------+ 09. C_ChartFloatingRAD *chart = NULL; 10. //+------------------------------------------------------------------+ 11. int OnInit() 12. { 13. chart = new C_ChartFloatingRAD("Indicator Chart Trade"); 14. 15. return (CheckPointer(chart) != POINTER_INVALID ? INIT_SUCCEEDED : INIT_FAILED); 16. } 17. //+------------------------------------------------------------------+ 18. void OnDeinit(const int reason) 19. { 20. delete chart; 21. } 22. //+------------------------------------------------------------------+ 23. void OnTick() {} 24. //+------------------------------------------------------------------+ 25. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 26. { 27. static ulong st_uTime = 0; 28. C_ChartFloatingRAD::stData info; 29. 30. switch (id) 31. { 32. case CHARTEVENT_OBJECT_CLICK: 33. info = (*chart).GetDataBuffer(); 34. if (st_uTime != info.uCount.TickCount) 35. { 36. st_uTime = info.uCount.TickCount; 37. PrintFormat("%u -- %s [%s] %d : %f <> %f", info.uCount.TickCount, info.IsDayTrade ? "DT" : "SW", EnumToString(info.Msg), info.Leverage, info.PointsTake, info.PointsStop); 38. }else Print("IGNORADO..."); 39. break; 40. } 41. } 42. //+------------------------------------------------------------------+
テストEAのソースコード
このコードは非常にシンプルでコンパクトであり、ほとんど説明不要です。しかし、一部の読者、特に初心者は、それがどのように機能するかを本当に理解できないかもしれません。これについて心配しないでください。すべての初心者は同様の困難に直面します。しかし、試して、勉強して、時間を投資し、規律を保ち、常に向上するよう努めれば、将来は間違いなく素晴らしいプロフェッショナルになるでしょう。困難に屈することはプロフェッショナルではありません。
では、コードを簡単に見てみましょう。数行しかないので、簡単に理解できるはずです。
前のトピックで紹介され、C_ChartFloatingRADクラスに存在するすべてのコードは、EAで使用されるときに要約されます。7行目にクラスを完全に含めていますが、これはコンパイラが考えるものとは正確には一致しません。したがって、9行目でポインタをグローバルに宣言します。これはC_ChartFloatingRADクラスにアクセスするために使用されます。これは混乱を招く可能性があります。ただし、それはクラスが指標コードと同じ方法でアクセスされると想像しているだけです。
実際、この方法でも可能ではありますが、現実的ではありません。その理由は、このクラスは指標なしで使用することを想定していないためです。マウス指標で使用されるC_Mouseクラスについても同様で、指標以外のコードで使用されるべきではありません。多くの人がこれをしたくなるかもしれませんが、これはやってはいけません。期待されるすべての安全性、モデリング、パフォーマンスは、元のコード以外のクラスを使用することを意図していないためです。つまり、指標と同じコーディング方法をEAに組み込むと、Chart Trade指標を使用する必要がないという点を実際に達成できます。これは事実です。
ただし、指標コードをEAに転送すると、そのような安定性を提供するように設計されていないため、システム全体の安定性とセキュリティに問題が発生する可能性があります。すべてに適切な場所があります。13行目でコンストラクタを呼び出してポインタを作成するときに、Chart Trade指標の名前として指定されたのと同じ名前を使用していることに注意してください。これにより、指標とEAの両方が機能します。すべてが自分の場所にいます。どれか1つに何か問題が起きたら、チャート上でやり直すだけです。
ほぼすべてのコードがまさにこれに集約されることに注意してください。指標名を指定し、OnChartEventイベントハンドラでCHARTEVENT_OBJECT_CLICKイベントをキャプチャして、何が起こったかを分析します。ここで重要な点が1つあります。マウスをクリックするたびに、重要なものをクリックしていないと思っていても、オブジェクトでクリックイベントが生成されます。これは、マウス指標が常にチャート上にある必要があるためです。この指標には水平線があり、これがオブジェクトです。したがって、マウスをクリックするたびに、この水平線によってイベントが生成されます。
しかし、システムはどのようにこの線のクリックと他のオブジェクトのクリックを区別できるのでしょうか。これは非常に興味深い質問であり、すぐに別の記事で取り上げる予定です。ただし、チャート上でさまざまなオブジェクトを使用する場合は、他の指標をすぐに追加する予定であるため、この点に留意する必要があります。ただし、これは将来の問題です。
問題は、33行目のオブジェクトクリックイベントがChart Trade指標バッファの内容を読み取ろうとすることです。これが成功すると、返されたデータを取得します。次に、34行目で、これがChart Trade関連のイベントなのか、それとも無視できる他の何かなのかを確認します。
実際にChart Tradeでイベントが生成され、それが注文システムのインタラクションボタンの1つをクリックしたことによって引き起こされた場合は、36行目でおこなったように静的変数の値を更新します。その後、何が起こったかを分析できるように、端末にメッセージを出力します。何らかの理由でイベントを無視する必要がある場合は、38行目を実行します。
結論
ビデオ01では、システムが実際にどのように機能するかを紹介しています。ただし、実際にシステムが動作しているのを見る機会に勝るものはありません。そのため、この記事の添付ファイルには、現在の状態のシステムが含まれています。
ビデオ 01:デモンストレーション
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11760




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