程式交易教學

誠邀您參加全球知名外匯經紀商OANDA的自營交易(Prop Trader)

報名OANDA自營交易(Prop Trader),並通過我們的考核,您就可以使用OANDA提供的資金進行交易,獲得高達90%的交易利潤分成。



全面升級——更多功能、更大靈活性!
優化了“固定最大虧損”,“每日虧損限制”等。查看詳情全新「Boost」計劃

500,000美元交易資金
您可以使用最高500,000美元的資金進行交易。

豐富的交易商品
您可以交易包括外匯、黃金、原油、股票指數等多種商品。



【MQL編程基礎】|製作簡易繪圖工具的方法

1.透過建立新檔案來設定顏色、尺寸的參數

在本篇章節中,將說明製作簡易繪圖工具的方法。 為工具設定以下三項功能。

    ①透過鍵盤P鍵,切換工具的ON/OFF開關。
    ②切換至ON時,能以滑鼠在圖表上拖曳畫線。
    ③透過鍵盤D鍵,刪除描繪的線條。
首先,在製作新檔案處選擇「自訂指標」,檔案名稱設定為「EasyPaint」。接著新增顏色與尺寸的參數。顏色的名稱為「CLR」、類型為「color」、初始數值為「White」,尺寸的名稱則是「SIZE」、類型為「int」、初始數值為「5」。在「自訂指標程式的事件處理常式」中勾選「OnChartEvent」,並在下一步點擊「完成」即是雛形。

自訂指標

2.定義可一次刪除物件的前綴

由於本次將使用物件,因此要在檔案上方的屬性「#property indicator_chart_window」之下定義前綴「PREFIX」。此動作是為了能夠一次刪除製作的物件。「MQLInfoString(MQL_PROGRAM_NAME)」將顯示指標的檔案名稱。

#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + “_”
其次,在「Custom indicator initialization function」下方設置「Custom indicator deinitialization function」,寫入下列使用OnDeinit函數的編碼。如此便會於自圖表中刪除指標時,一併刪除相關的物件。

void OnDeinit(const int reason)

{

if (reason == REASON_REMOVE) ObjectsDeleteAll(0, PREFIX);

}
另外,在檔案上方的尺寸參數「input int SIZE = 5;」之下,寫入確認開關ON/OFF的變數、以及儲存游標位置的變數。

bool paint = false;

int posX, posY;

3.確認分配給P鍵的編號

接下來,將繼續製作OnChartEvent函數內的開關功能。為了確認鍵盤的操作方式,並在按下P鍵時能夠切換開關的ON/OFF,首先需確認分配給P鍵的編號。利用可得出所按按鍵編號的「CHARTEVENT_KEYDOWN」,並試著取得編號。

if (id == CHARTEVENT_KEYDOWN) {

Print(sparam);

}
如此進行編譯並設定圖表,當按下鍵盤的P鍵時,就會在終端視窗的「Expert」標籤中顯示「25」。此25即為分配給P鍵的編號。

P鍵的編號

4.按下鍵盤P鍵切換ON/OFF開關

上述利用了開關的ON/OFF切換,確認完分配給P鍵的編號。接下來,將使用此經過確認的編號,寫入按下P鍵時所執行的處理動作。

首先利用if文體,使sparam為「25」時切換開關。開關為OFF時paint為ON,開關為ON時paint則是OFF。

if (id == CHARTEVENT_KEYDOWN) {

if (sparam == “25”) {

if (!paint) {

paint = true;

} else {

paint = false;

}

}

Print(sparam);

}

}

5.以Label物件顯示文字

為了讓開關的狀態一目了然,將以Label物件顯示大型文字。可從MQL4幫助檔中,複製Label物件的範例編碼。於MQL4相關參考目錄中點選「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」,便會顯示物件一覽表。從中選擇「OBJ_LABEL」,並將預先準備的「Create a text label」編碼複製貼上於檔案的下方。

刪除不需要的「//— reset the error value」「ResetLastError();」2行,以及「Print(__FUNCTION__,」「”: failed to create text label! Error code = “,GetLastError());」2行。

另外,上方參數的「// subwindow index」「// chart corner for anchoring」「// text slope」等3行也無需使用,可加上「//」作為備註,將「if(!ObjectCreate(chart_ID, name, OBJ_LABEL, sub_window, 0, 0))」的「sub_window」處以及「ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, angle);」的「angle」處一併變更為「0」,「ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, corner);」的「corner」處則變更為「CORNER_LEFT_UPPER」。

//+——————————————————————+

//| Create a text label |

//+——————————————————————+

bool LabelCreate(const long chart_ID = 0, // chart’s ID

const string name = “Label”, // label name

// const int sub_window = 0, // subwindow index

const int x = 0, // X coordinate

const int y = 0, // Y coordinate

// const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring

const string text = “Label”, // text

const string font = “Arial”, // font

const int font_size = 10, // font size

const color clr = clrRed, // color

// const double angle = 0.0, // text slope

const ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER, // anchor type

const bool back = false, // in the background

const bool selection = false, // highlight to move

const bool hidden = true, // hidden in the object list

const long z_order = 0) // priority for mouse click

{

//— create a text label

if(!ObjectCreate(chart_ID, name, OBJ_LABEL, 0, 0, 0)) {

return(false);

}

//— set label coordinates

ObjectSetInteger(chart_ID, name, OBJPROP_XDISTANCE, x);

ObjectSetInteger(chart_ID, name, OBJPROP_YDISTANCE, y);

//— set the chart’s corner, relative to which point coordinates are defined

ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);

//— set the text

ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);

//— set text font

ObjectSetString(chart_ID, name, OBJPROP_FONT, font);

//— set font size

ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);

//— set the slope angle of the text

ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, 0);

//— set anchor type

ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);

//— set color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— display in the foreground (false) or background (true)

ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);

//— enable (true) or disable (false) the mode of moving the label by mouse

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);

//— hide (true) or display (false) graphical object name in the object list

ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);

//— set the priority for receiving the event of a mouse click in the chart

ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);

//— successful execution

return(true);

}
在此狀態下使用LabelCreate。寫入畫線處理動作的位置,則是方才if文體中的「paint = true;」下方。Id為0、名稱為「PREFIX + “switch”」、X為「5」、Y為「15」、文字為「PAINT」、字體為粗體字的「Arial Black」、尺寸為「20」、顏色為參數指定的顏色、錨定於左上方,其他則維持初始數值。

LabelCreate(0, PREFIX + “Switch”, 5, 15, “PAINT”, “Arial Black”, 20, CLR, ANCHOR_LEFT_UPPER);
另外,因希望在開關切換至OFF時刪除Label物件,故應在「paint = false;」下方寫入下列使用ObjectDelete的編碼。

ObjectDelete(0, PREFIX + “Switch”);
如此進行編譯並按下P鍵,就會在圖表左上方看見「PAINT」字樣。在此狀態下,再按一次P鍵即可將其刪去。

PAINT

6.設定成拖曳也不會移動的圖表

接下來,將在開關切換為ON時,使用「MOUSE_MOVE」來描繪線條。但是,若在圖表上透過拖曳游標來畫線,圖表將會出現移動,因此需避免此狀況發生。舉例來說,因拖曳物件時圖表不會隨之移動,就能夠利用此特性,在開關轉為ON時置入虛擬物件,將圖表設定為不會移動。首先於「posX」置入「lparam」、於「posY」置入「dparam」。

if (id == CHARTEVENT_MOUSE_MOVE) {

posX = (int)lparam;

posY = (int)dparam;
其後在「LabelCreate(0, PREFIX + “Switch”, 5, 15, “PAINT”, “Arial Black”, 20, CLR, ANCHOR_LEFT_UPPER);」下方添加以下編碼。名稱為「Point」,並在文字處以空白表示,讓物件無法被看見。

LabelCreate(0, PREFIX + “Point”, posX, posY, ” “, “メイリオ”, 10000, clrNONE, ANCHOR_CENTER, false, true);
當開關轉為OFF時,若希望刪除此虛擬物件,便須在「ObjectDelete(0, PREFIX + “Switch”);」下方新增以下編碼。

ObjectDelete(0, PREFIX + “Point”);
並讓製作的虛擬物件隨著游標位置移動。另外,為了避免在點擊兩下時遭到取消選擇,將OBJPROP_SELECTED設為隨時有效。

if (paint) {

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_XDISTANCE, posX);

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_YDISTANCE, posY);

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_SELECTED, true);

}
接著,為了啟動「MOUSE_MOVE」,於OnInit函數中的「//— indicator buffers mapping」下方寫入以下編碼。

ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
如此進行編譯並按下P鍵,圖表便不會因滑鼠拖曳而移動。

另外,亦可配合運用ChartSetInteger()的CHART_MOUSE_SCROLL。

ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
依照上方所示設定為false,如此即便在圖表上拖曳,圖表也不會滑動。

7.在圖表上拖曳時繪製線條

上述文章中,實行了透過P鍵來切換ON/OFF開關,並讓圖表不會因滑鼠拖曳而移動。接下來,將寫入游標在圖表上拖曳時(點擊並移動時)繪製線條的處理動作。

首先在「posY = (int)dparam;」下方,定義記憶前一個游標座標的函數「preX」「preY」。

static int preX, preY;
利用if文體,當點擊滑鼠時,若與儲存的座標相異,便會在該處執行繪圖處理。將繪製的圖案設定為「●」標記。

if (sparam == “1”) {

if (posX != preX || posY != preY) {

string name = PREFIX + “Parint_” + (string)preX + “_” + (string)preY;

LabelCreate(0, name, posX, posY, “●”, “メイリオ”, SIZE, CLR, ANCHOR_CENTER);

}

preX = posX;

preY = posY;

}
由於希望在paint處理為OFF時重新設定,因此在「if (paint)」新增else。

} else {

preX = 0;

preY = 0;

}
如此進行編譯並按下P鍵,就能在拖曳游標時繪製線條與文字。

paint

8.以D鍵刪除繪製的線條

最後的設定,是當按下D鍵時刪除繪製的線條。分配給D鍵的編號為「32」。運用if文體,當「sparam」為32時刪除元件。將「Print(sparam);」替換為以下內容。

if (sparam == “32”) ObjectsDeleteAll(0, PREFIX);
如此進行編譯並按下D,方才描繪的物件便會消失。

描繪的物件消失

更甚,若添加將paint的開關也設定為OFF的「paint = false;」,即可完成簡易的繪圖工具。

if (sparam == “32”) {

ObjectsDeleteAll(0, PREFIX);

paint = false;

}

9.原始碼

本次製作的原始碼如以下所示。

//+——————————————————————+

//| EasyPaint.mq4 |

//| Copyright 2022, MetaQuotes Software Corp. |

//| https://www.mql5.com |

//+——————————————————————+

#property copyright “Copyright 2022, MetaQuotes Software Corp.”

#property link “https://www.mql5.com”

#property version “1.00”

#property strict

#property indicator_chart_window

#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + “_”

//— input parameters

input color CLR = clrWhite;

input int SIZE = 5;

bool paint = false;

int posX, posY;

//+——————————————————————+

//| Custom indicator initialization function |

//+——————————————————————+

int OnInit()

{

//— indicator buffers mapping

ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

//—

return(INIT_SUCCEEDED);

}

//+——————————————————————+

//| Custom indicator deinitialization function |

//+——————————————————————+

void OnDeinit(const int reason)

{

if (reason == REASON_REMOVE) ObjectsDeleteAll(0, PREFIX);

}

//+——————————————————————+

//| Custom indicator iteration function |

//+——————————————————————+

int OnCalculate(const int rates_total,

const int prev_calculated,

const datetime &time[],

const double &open[],

const double &high[],

const double &low[],

const double &close[],

const long &tick_volume[],

const long &volume[],

const int &spread[])

{

//—

//— return value of prev_calculated for next call

return(rates_total);

}

//+——————————————————————+

//| ChartEvent function |

//+——————————————————————+

void OnChartEvent(const int id,

const long &lparam,

const double &dparam,

const string &sparam)

{

//—

if (id == CHARTEVENT_KEYDOWN) {

if (sparam == “25”) {

if (!paint) {

paint = true;

LabelCreate(0, PREFIX + “Switch”, 5, 15, “PAINT”, “Arial Black”, 20, CLR, ANCHOR_LEFT_UPPER);

LabelCreate(0, PREFIX + “Point”, posX, posY, ” “, “メイリオ”, 10000, clrNONE, ANCHOR_CENTER, false, true);

} else {

paint = false;

ObjectDelete(0, PREFIX + “Switch”);

ObjectDelete(0, PREFIX + “Point”);

}

}

if (sparam == “32”) {

ObjectsDeleteAll(0, PREFIX);

paint = false;

}

}

if (id == CHARTEVENT_MOUSE_MOVE) {

posX = (int)lparam;

posY = (int)dparam;

static int preX, preY;

if (paint) {

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_XDISTANCE, posX);

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_YDISTANCE, posY);

ObjectSetInteger(0, PREFIX + “Point”, OBJPROP_SELECTED, true);

if (sparam == “1”) {

if (posX != preX || posY != preY) {

string name = PREFIX + “Parint_” + (string)preX + “_” + (string)preY;

LabelCreate(0, name, posX, posY, “●”, “メイリオ”, SIZE, CLR, ANCHOR_CENTER);

}

preX = posX;

preY = posY;

}

} else {

preX = 0;

preY = 0;

}

}

}

//+——————————————————————+

//| Create a text label |

//+——————————————————————+

bool LabelCreate(const long chart_ID = 0, // chart’s ID

const string name = “Label”, // label name

// const int sub_window = 0, // subwindow index

const int x = 0, // X coordinate

const int y = 0, // Y coordinate

// const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring

const string text = “Label”, // text

const string font = “Arial”, // font

const int font_size = 10, // font size

const color clr = clrRed, // color

// const double angle = 0.0, // text slope

const ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER, // anchor type

const bool back = false, // in the background

const bool selection = false, // highlight to move

const bool hidden = true, // hidden in the object list

const long z_order = 0) // priority for mouse click

{

//— create a text label

if(!ObjectCreate(chart_ID, name, OBJ_LABEL, 0, 0, 0)) {

return(false);

}

//— set label coordinates

ObjectSetInteger(chart_ID, name, OBJPROP_XDISTANCE, x);

ObjectSetInteger(chart_ID, name, OBJPROP_YDISTANCE, y);

//— set the chart’s corner, relative to which point coordinates are defined

ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);

//— set the text

ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);

//— set text font

ObjectSetString(chart_ID, name, OBJPROP_FONT, font);

//— set font size

ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);

//— set the slope angle of the text

ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, 0);

//— set anchor type

ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);

//— set color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— display in the foreground (false) or background (true)

ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);

//— enable (true) or disable (false) the mode of moving the label by mouse

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);

//— hide (true) or display (false) graphical object name in the object list

ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);

//— set the priority for receiving the event of a mouse click in the chart

ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);

//— successful execution

return(true);

}

將EA自動程式交易應用於外匯與差價合約交易中

EA

我們以圖文形式詳細介紹有關EA自動程式交易的基本知識,以及在MT4/MT5平台上的安裝、參數設定方法、編碼等等內容。另外,對持有OANDA帳戶的客戶,還可以免費使用我們的獨有EA與指標工具。

誠邀您參加全球知名外匯經紀商OANDA的自營交易(Prop Trader)

報名OANDA自營交易(Prop Trader),並通過我們的考核,您就可以使用OANDA提供的資金進行交易,獲得高達90%的交易利潤分成。



全面升級——更多功能、更大靈活性!
優化了“固定最大虧損”,“每日虧損限制”等。查看詳情全新「Boost」計劃

500,000美元交易資金
您可以使用最高500,000美元的資金進行交易。

豐富的交易商品
您可以交易包括外匯、黃金、原油、股票指數等多種商品。