程式交易教學

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

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



限時優惠代碼
在購買鈦金挑戰賽時輸入“TITANIUM30”,即獲得30%的折扣(優惠截止日期為2024年4月30日)。

優化了挑戰塞交易規則
無最低交易天數限制等優化了挑戰賽的交易規則。

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

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



製作重疊顯示Tick圖與1分鐘K線的自動交易程式

新增匯入Tick資訊與時間資訊的緩衝器

本文將說明如何在副窗口中重疊顯示Tick圖與1分鐘K線。首先介紹如何顯示Tick圖。

首先,在製作新檔案時選擇「自訂指標」,並將檔案命名為「Tick_and_Bar」。參數將可指定計算K線的數量。名稱應為「BARS」、初始值為「1000」。

自訂指標

在「自訂指標程式的事件處理常式」中,「OnTimer」「OnChartEvent」皆無需勾選,直接進入下一步,並在「繪製自訂性能指標方案」設定中,登錄含有數據的兩個緩衝器。

一個是匯入Tick資訊的緩衝器,標籤為「Tick」、顏色為「White」,另一個是匯入時間資訊的緩衝器,標籤為「TimeM1」、顏色為「Red」。如此點擊「完成」即可呈現雛形。

Tick資訊的緩衝器

開啟新檔案時,將修正上方的屬性。首先,將「indicator_chart_window」變更為「indicator_separate_window」,以便顯示於副窗口中。

#property indicator_ separate _window
接下來,由於不需顯示記憶時間資訊的「TimeM1」,因此樣式(type)的「DRAW_LINE」改變為「DRAW_NONE」,並刪除其下的「color」「style」「width」3行。本次將使用元件,故為了能夠一次刪除,應先定義接頭詞的「PREFIX」。

#property indicator_type2 DRAW_NONE

#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + “_”
另外,由於緩衝器的名稱過長,可如「TickBuffer」→「Tick」將「Buffer」省略予以縮短。

double Tick[];

double TimeM1[];
同樣地,用於 OnInit函數中的緩衝器名稱也能如下所示來變更。

SetIndexBuffer(0,Tick);

SetIndexBuffer(1,TimeM1);

在副窗口中顯示Tick圖

接下來將嘗試在副窗口中顯示Tick圖。

在OnCalculate函數下方寫入計算公式。計算的K線數量指定為較少的「BARS」或「Bars-2」。首先,雖然要在「Tick[0]」中寫入「Bid」,但每次寫入時,若不移動一個緩衝器,則相同的數值將會逐漸遭到改寫。因此應輸入1根K線之前的數值。這樣移動每1根K線的處理過程,將會在Tick[0]含有數據時執行。

int limit = MathMin(BARS, Bars – 2);

if (Tick[0] != EMPTY_VALUE) {

for (int i = limit; i > 0; i–) {

Tick[i] = Tick[i – 1];

}

}

Tick[0] = Bid;
如此進行編譯並設定圖表,便會在副窗口中顯示K線圖。

副窗口中顯示K線圖

新增「TimeM1」的相關公式

以同樣的方式,新增匯入時間資訊的「TimeM1」內容。在「TimeM1[0]」中匯入1分鐘K線的時間,並在每次進行時刪除元件。另外,也應先重設「limit+1」以顯示範圍外的數值。

int limit = MathMin(BARS, Bars – 2);

if (Tick[0] != EMPTY_VALUE) {

for (int i = limit; i > 0; i–) {

Tick[i] = Tick[i – 1];

TimeM1[i] = TimeM1[i – 1];

}

}

Tick[0] = Bid;

TimeM1[0] = (double)iTime(NULL, PERIOD_M1, 0);

Tick[limit + 1] = EMPTY_VALUE;

TimeM1[limit + 1] = EMPTY_VALUE;

ObjectsDeleteAll(0, PREFIX);

取得1分鐘K線的4個價格

目前已在副窗口中顯示Tick圖,並完成了重疊1分鐘K線的準備工作。接下來,將利用緩衝器來繪製1分鐘的K線。

首先使用if文體,讓「TimeM1」數值為空白時不會執行處理。接下來以「iBarShift」顯示1分鐘K線的編號,藉以分別取得4個價格。

for (int i = limit; i >= 0; i–) {

if (TimeM1[i] == EMPTY_VALUE) continue;

int bar = iBarShift(NULL, PERIOD_M1, (datetime)TimeM1[i]);

double op = iOpen(NULL, PERIOD_M1, bar);

double cl = iClose(NULL, PERIOD_M1, bar);

double hi = iHigh(NULL, PERIOD_M1, bar);

double lo = iLow(NULL, PERIOD_M1, bar);
此處應定義K線的顏色。將陽線設為紅色、陰線為藍色。

color clr = clrWhite;

if (cl > op) clr = clrRed;

else if (cl < op) clr = clrBlue;

沿用元件的範例編碼

接下來將使用if文體,在與先前的K線相比之下、當1分鐘K線的資訊出現變化時繪製新K線,若相同則會更新資訊。

if (TimeM1[i] != TimeM1[i + 1]) {

} else {

}
首先,將寫入1分鐘K線的資訊與先前K線不同時的處理過程。每次描繪新K線時,將利用元件的趨勢線與矩形,因此可從MQL4幫助檔中複製範例編碼加以使用。

在MQL4幫助檔的目錄中點選「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」,即可看見元件一覽。從中選擇「OBJ_TREND」,並將預先準備的「Create a trend line by the given coordinates」編碼複製貼上於檔案下方。

同樣地,從元件一覽中選擇「OBJ_RECTANGLE」,並複製「Create rectangle by the given coordinates」編碼複製貼至檔案下方。

如兩者皆欲設定背景,可將「// in the background」的「back = false」變成「back = true」。因無需進行選擇,故將「// highlight to move」的「selection = true」改為「selection = false」。

另外,趨勢線的「//— set anchor points’ coordinates if they are not set」到「ResetLastError();」4行、「Print(__FUNCTION__,」「”: failed to create a trend line! Error code = “, GetLastError());」兩行、矩形的「//— set anchor points’ coordinates if they are not set」到「ResetLastError();」4行、以及「Print(__FUNCTION__,」「”: failed to create a rectangle! Error code = “, GetLastError());」兩行皆無需使用,可予以刪除。

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

//| Create a trend line by the given coordinates |

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

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

const string name = “TrendLine”, // line name

const int sub_window = 0, // subwindow index

datetime time1 = 0, // first point time

double price1 = 0, // first point price

datetime time2 = 0, // second point time

double price2 = 0, // second point price

const color clr = clrRed, // line color

const ENUM_LINE_STYLE style = STYLE_SOLID, // line style

const int width = 1, // line width

const bool back = true, // in the background

const bool selection = false, // highlight to move

const bool ray_right = false, // line’s continuation to the right

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

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

{

//— create a trend line by the given coordinates

if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2)) { return(false);

}

//— set line color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— set line display style

ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);

//— set line width

ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);

//— 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 line by mouse

//— when creating a graphical object using ObjectCreate function, the object cannot be

//— highlighted and moved by default. Inside this method, selection parameter

//— is true by default making it possible to highlight and move the object

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);

//— enable (true) or disable (false) the mode of continuation of the line’s display to the right

ObjectSetInteger(chart_ID, name, OBJPROP_RAY_RIGHT, ray_right);

//— 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);

}

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

//| Create rectangle by the given coordinates |

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

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

const string name = “Rectangle”, // rectangle name

const int sub_window = 0, // subwindow index

datetime time1 = 0, // first point time

double price1 = 0, // first point price

datetime time2 = 0, // second point time

double price2 = 0, // second point price

const color clr = clrRed, // rectangle color

const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines

const int width = 1, // width of rectangle lines

const bool fill = false, // filling rectangle with color

const bool back = true, // 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 rectangle by the given coordinates

if(!ObjectCreate(chart_ID, name, OBJ_RECTANGLE, sub_window, time1, price1, time2, price2)) {

return(false);

}

//— set rectangle color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— set the style of rectangle lines

ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);

//— set width of the rectangle lines

ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);

//— enable (true) or disable (false) the mode of filling the rectangle

ObjectSetInteger(chart_ID, name, OBJPROP_FILL, fill);

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

ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);

//— enable (true) or disable (false) the mode of highlighting the rectangle for moving

//— when creating a graphical object using ObjectCreate function, the object cannot be

//— highlighted and moved by default. Inside this method, selection parameter

//— is true by default making it possible to highlight and move the object

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);

}
如此進行編譯並點擊圖表,K線的顏色就會自左邊移至右邊。

以元件繪製1分鐘K線

在中間段落中,說明了如何設定趨勢線與矩形來繪製1分鐘K線。以下將運用這些元件來繪製1分鐘K線。

首先以矩形寫入1分鐘K線的實體。先定義「name」、名稱為「name + “Body”」,副窗口的部分、使用以「ChartWindowFind」設定指標的副窗口編號,時間為「Time[i]」、價格為開盤價至收盤價、顏色為則是已定義的顏色。

string name = PREFIX + (string)bar + “_”;

RectangleCreate(0, name + “Body”, ChartWindowFind(), Time[i], op, Time[i], cl, clr);
接下來是趨勢線。名稱為「name + “Pin”」、價格為開盤價至收盤價,其他則與矩形相同。

TrendCreate(0, name + “Pin”, ChartWindowFind(), Time[i], hi, Time[i], lo, clr);
接下來,將寫入當1分鐘K線的資訊與先前相同時的處理過程。為了更新K線的資訊,使用「ObjectMove」變更元件的座標。至於價格的部分,顯示實體的「Body」為收盤價,顯示影線的「Pin」則反應最高價與最低價。

因要將影線繪製於實體的中央,故在for文體上添加「int barStart = 0;」、並在「TrendCreate(0, name + “Pin”, ChartWindowFind(), Time[i], hi, Time[i], lo, clr);」下添加「barStart = i;」,預先記憶K線最初出現的位置。自K線最初出現處,加上目前的位置再除以2,便是實體的中央部位,故將於該處繪製影線。

ObjectMove(0, name + “Body”, 1, Time[i], cl);

ObjectMove(0, name + “Pin”, 0, Time[(barStart + i) / 2], hi);

ObjectMove(0, name + “Pin”, 1, Time[(barStart + i) / 2], lo);
另外,使用「ObjectSetInteger」指定實體與影線的顏色。

ObjectSetInteger(0, name + “Body”, OBJPROP_COLOR, clr);

ObjectSetInteger(0, name + “Pin”, OBJPROP_COLOR, clr);
如此進行編譯,子視窗的點線圖上便會重疊顯示1分鐘K線。

1分鐘K線

以元件繪製1分鐘線條

當開盤價與收盤價一致時,實體(矩形)的高度將會變成0,如此便無法顯示十字線。因此應當開盤價等於收盤價時,應在收盤價加上最低價波動點(若為美元/日圓便是0.1錢)的一半,並顯示十字線。添加下列if文體於「ObjectMove(0, name + “Body”, 1, Time[i], cl);」上方。

if (cl ==op) cl += _Point / 2;
另外,由於目前的影線過細,可將其寬度增加。將趨勢線「// line width」的初始值從「width = 1」變成「width = 3」。

const int width = 3, // line width
接著進行編譯即可完成。如此重疊顯示Tick圖與1分鐘K線,即可仔細確認1分鐘線條的內容。在操作以秒為單位的買賣時,將可作為實用的指標。

重疊顯示Tick圖與1分鐘K線

原始碼

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

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

//| Tick_and_Bar.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_separate_window

#property indicator_buffers 2

#property indicator_plots 2

//— plot Tick

#property indicator_label1 “Tick”

#property indicator_type1 DRAW_LINE

#property indicator_color1 clrWhite

#property indicator_style1 STYLE_SOLID

#property indicator_width1 1

//— plot TimeM1

#property indicator_label2 “TimeM1”

#property indicator_type2 DRAW_NONE

#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + “_”

//— input parameters

input int BARS = 1000;

//— indicator buffers

double Tick[];

double TimeM1[];

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

//| Custom indicator initialization function |

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

int OnInit()

{

//— indicator buffers mapping

SetIndexBuffer(0, Tick);

SetIndexBuffer(1, TimeM1);

//—

return(INIT_SUCCEEDED);

}

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

//| 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[])

{

//—

int limit = MathMin(BARS, Bars – 2);

if (Tick[0] != EMPTY_VALUE) {

for (int i = limit; i > 0; i–) {

Tick[i] = Tick[i – 1];

TimeM1[i] = TimeM1[i – 1];

}

}

Tick[0] = Bid;

TimeM1[0] = (double)iTime(NULL, PERIOD_M1, 0);

Tick[limit + 1] = EMPTY_VALUE;

TimeM1[limit + 1] = EMPTY_VALUE;

ObjectsDeleteAll(0, PREFIX);

int barStart = 0;

for (int i = limit; i >= 0; i–) {

if (TimeM1[i] == EMPTY_VALUE) continue;

int bar = iBarShift(NULL, PERIOD_M1, (datetime)TimeM1[i]);

double op = iOpen(NULL, PERIOD_M1, bar);

double cl = iClose(NULL, PERIOD_M1, bar);

double hi = iHigh(NULL, PERIOD_M1, bar);

double lo = iLow(NULL, PERIOD_M1, bar);

color clr = clrWhite;

if (cl > op) clr = clrRed;

else if (cl < op) clr = clrBlue;

string name = PREFIX + (string)bar + “_”;

if (TimeM1[i] != TimeM1[i + 1]) {

RectangleCreate(0, name + “Body”, ChartWindowFind(), Time[i], op, Time[i], cl, clr);

TrendCreate(0, name + “Pin”, ChartWindowFind(), Time[i], hi, Time[i], lo, clr);

barStart = i;

} else {

if (cl ==op) cl += _Point / 2;

ObjectMove(0, name + “Body”, 1, Time[i], cl);

ObjectMove(0, name + “Pin”, 0, Time[(barStart + i) / 2], hi);

ObjectMove(0, name + “Pin”, 1, Time[(barStart + i) / 2], lo);

ObjectSetInteger(0, name + “Body”, OBJPROP_COLOR, clr);

ObjectSetInteger(0, name + “Pin”, OBJPROP_COLOR, clr);

}

}

//— return value of prev_calculated for next call

return(rates_total);

}

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

//| Create a trend line by the given coordinates |

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

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

const string name = “TrendLine”, // line name

const int sub_window = 0, // subwindow index

datetime time1 = 0, // first point time

double price1 = 0, // first point price

datetime time2 = 0, // second point time

double price2 = 0, // second point price

const color clr = clrRed, // line color

const ENUM_LINE_STYLE style = STYLE_SOLID, // line style

const int width = 3, // line width

const bool back = true, // in the background

const bool selection = false, // highlight to move

const bool ray_right = false, // line’s continuation to the right

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

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

{

//— create a trend line by the given coordinates

if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2)) {

return(false);

}

//— set line color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— set line display style

ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);

//— set line width

ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);

//— 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 line by mouse

//— when creating a graphical object using ObjectCreate function, the object cannot be

//— highlighted and moved by default. Inside this method, selection parameter

//— is true by default making it possible to highlight and move the object

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);

ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);

//— enable (true) or disable (false) the mode of continuation of the line’s display to the right

ObjectSetInteger(chart_ID, name, OBJPROP_RAY_RIGHT, ray_right);

//— 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);

}

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

//| Create rectangle by the given coordinates |

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

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

const string name = “Rectangle”, // rectangle name

const int sub_window = 0, // subwindow index

datetime time1 = 0, // first point time

double price1 = 0, // first point price

datetime time2 = 0, // second point time

double price2 = 0, // second point price

const color clr = clrRed, // rectangle color

const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines

const int width = 1, // width of rectangle lines

const bool fill = false, // filling rectangle with color

const bool back = true, // 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 rectangle by the given coordinates

if(!ObjectCreate(chart_ID, name, OBJ_RECTANGLE, sub_window, time1, price1, time2, price2)) {

return(false);

}

//— set rectangle color

ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);

//— set the style of rectangle lines

ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);

//— set width of the rectangle lines

ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);

//— enable (true) or disable (false) the mode of filling the rectangle

ObjectSetInteger(chart_ID, name, OBJPROP_FILL, fill);

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

ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);

//— enable (true) or disable (false) the mode of highlighting the rectangle for moving

//— when creating a graphical object using ObjectCreate function, the object cannot be

//— highlighted and moved by default. Inside this method, selection parameter

//— is true by default making it possible to highlight and move the object

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提供的資金進行交易,獲得高達80%的交易利潤分成。



限時優惠代碼
在購買鈦金挑戰賽時輸入“TITANIUM30”,即獲得30%的折扣(優惠截止日期為2024年4月30日)。

優化了挑戰塞交易規則
無最低交易天數限制等優化了挑戰賽的交易規則。

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

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