基礎から学ぶシステムトレード
シストレブログ人気ランキング  

シストレ徹底攻略シストレマスターへの道ワールド・トレーディング・エッジ基礎から学ぶシステムトレードシストレニュースシストレツールシストレナビTOPへ

 

著書のご紹介

2010年09月06日(月)

MQL5でEA(2) [MetaTrader5]

今回はEAに欠かせないトレードに関する関数についてみてみましょう。

MQL4では、トレードに関して以下の4つの関数が用意されていました。

OrderSend() - 成行、指値、逆指値売買オーダーの送信
OrderClose() - オープンポジションの決済
OrderDelete() - 指値、逆指値の待機オーダーのキャンセル
OrderModify() - オーダーの変更

MQL5では、これらのトレードに関する機能は、一つの関数OrderSend()に集約されています。但し、このOrderSend()という関数は、MQL4の場合と同じ名前ですが、使い方は全く違います

まず、関数の宣言ですが、
bool  OrderSend(
MqlTradeRequest& request, // query structure
MqlTradeResult& result // structure of the answer
);

となっています。たったこれだけです。つまり、引数は二つしかないのです。

但し、引数の型は、それぞれ「MqlTradeRequest」と、「MqlTradeResult」となっています。

MqlTradeRequest、MqlTradeResultという型なんて聞いたことがないと思いますが、これはデータ型ではなく、MQL5で予め定義されている構造体の識別名なのです。

それぞれの構造体は以下のように定義されています。

struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type
ulong magic; // Expert Advisor ID (magic number)
ulong order; // Order ticket
string symbol; // Trade symbol
double volume; // Requested volume for a deal in lots
double price; // Price
double stoplimit; // StopLimit level of the order
double sl; // Stop Loss level of the order
double tp; // Take Profit level of the order
ulong deviation; // Maximal possible deviation from the requested price
ENUM_ORDER_TYPE type; // Order type
ENUM_ORDER_TYPE_FILLING type_filling; // Order execution type
ENUM_ORDER_TYPE_TIME type_time; // Order execution time
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
string comment; // Order comment
};

struct MqlTradeResult
{
uint retcode; // Operation return code
ulong deal; // Deal ticket, if it is performed
ulong order; // Order ticket, if it is placed
double volume; // Deal volume, confirmed by broker
double price; // Deal price, confirmed by broker
double bid; // Current Bid price
double ask; // Current Ask price
string comment; // Broker comment to operation (by default it is filled by the operation description)
};

OrderSend()の仕組みは、大雑把に言うとこうです。MqlTradeRequestの構造体変数でオーダーの種類や価格、SL、TPを指定してOrderSend()に渡し、その結果がMqlTradeResultの構造体変数に格納されて返ってくるといった感じです。

ここでは、それぞれの構造体の詳しい説明は省略します。とりあえず、指値買いオーダーを送信する例についてみてみます。

まずは、MqlTradeRequest、MqlTradeResultの構造体変数を宣言します。
MqlTradeRequest request;
MqlTradeResult result;

この例では、requestresult というのが変数名ですが、必ずしもこの名前にする必要はありません。

次に request という構造体変数のそれぞれのフィールドに適切な値を代入します。

action」というフィールドで、成行、指値、修正、キャンセルなどの指示を行います。それぞれ識別子が決まっており、指値、逆指値オーダーの場合、「TRADE_ACTION_PENDING」を代入します。
request.action = TRADE_ACTION_PENDING;

symbol」というフィールドには、対象となる通貨ペアを代入します。通常は、
request.symbol = _Symbol;

と指定すれば、プログラムを挿入したチャートの通貨ペアとなります。

volume」は売買ロット数です。ここでは、0.1ロットを指定してみます。
request.volume = 0.1;

price」は指値の価格です。ここでは、USD/JPYを対象として80円に設定してみます。
request.price = 80.00;

type」というフィールドでは、買い、売りなどのオーダーの種類を指定します。指値買いの場合、「ORDER_TYPE_BUY_LIMIT」を指定します。
request.type = ORDER_TYPE_BUY_LIMIT;

これで必要最低限の設定は終わりましたので、OrderSend()を実行します。
OrderSend(request,result);

これで実際に指値オーダーが入ればOKですが、うまくいかない場合には、エラーコードを表示させると原因がつかみやすいでしょう。

OrderSend()のエラーコードは、resultのretcodeフィールドに格納されて戻ってきます。
Print("retcode = ",result.retcode);

のように表示させれば、ToolboxウィンドウのExpertsタブにエラーコードが表示されます。

画像(450x286)・拡大画像(800x510)

このように「retcode = 10009」となればOKです。10009というコードはオーダーが正常に実行されたことを意味します。

ただ、その下の行では、「retcode = 10027」となっています。これは、AutoTdradingが無効になっていて、オーダーが送信できなかったということを表します。スクリプトプログラムでも、オーダーを実行するためにはツールバーのAutoTradingのボタンを押して有効にしておく必要があります。

result.retcode は、他にも様々なエラーに対応したコードを返します。詳しくは、MQL5のレファレンスマニュアルのReturn Codes of the Trade Serverを参照してください。

最後に、今回説明したプログラムリストをつけておきます。

void OnStart()
{
MqlTradeRequest request;
MqlTradeResult result;

request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.1;
request.price = 80.0;
request.type = ORDER_TYPE_BUY_LIMIT;

OrderSend(request,result);
Print("retcode = ",result.retcode);
}

Posted at 15時20分 パーマリンク


2010年08月30日(月)

MQL5でEA(1) [MetaTrader5]

さて、今回からMQL5でEAを作成してみます。

「EA」は「Expert Advisor」の略で、日本語に直訳すれば「専門の相談員」となります。でも、これでは意味がわからないので、「EA」という言葉は普及しないかなと思っていたのですが、今ではメタトレーダーの自動売買プログラムという意味ですっかり定着したようです。

MQL5のEAも他のプログラム同様、MQL4とは互換性がないので、何回かにわけて説明していきます。

まず、メタエディターからFile - Newを選んでExpert Advisorを選択すると、以下のような新規プログラムが作成されます。

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---

//---
return(0);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---

}
//+------------------------------------------------------------------+

ここで、OnInit()、OnDeinit()、OnTick()の3つの関数があります。OnInit()、OnDeinit()はカスタム指標プログラムで出てきたものと同じで、それぞれプログラムの最初と最後に呼ばれる関数です。

OnTick()というのは初めて出てきましたが、これは MQL4での start()と同じものです。ティック毎に実行される関数です。

今回はまず準備として、MQL4で定義済み変数としてすぐに使えたものをMQL5用に用意しておきましょう。

最初にBidとAskです。BidとAskはプログラム全体で使えるように外部変数として宣言しておきます。

そして、以前の記事のように構造体MqlTickSymbolInfoTick()という関数を使って取得します。

ただ、これらを書く場所ですが、レートの更新はティック毎だけでなく、トレードの直前に行うこともあるので、RefreshRates()という関数(これはMQL4では組込み関数でした)を作って、そこに書いておくことにします。

以下のリストは、ティック毎にBid、Askを表示させるだけのEAです。

double Bid, Ask;

// 初期化関数
int OnInit()
{
return(0);
}

// 終了関数
void OnDeinit(const int reason)
{
}

// ティック関数
void OnTick()
{
if(!RefreshRates()) return;
Print("Bid=", Bid);
Print("Ask=", Ask);
}

// レートの更新
bool RefreshRates()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick)) return(false);
Bid = tick.bid;
Ask = tick.ask;
return(true);
}

いくつかif文が出てきますが、これらは「念のため」といったところです。

SymbolInfoTick()は、正常にレートが取得できなかった場合にfalseを返すので、その場合RefreshRates()もfalseを返すようにしています。なお、

if(!SymbolInfoTick(_Symbol, tick)) return(false);

は、
if(SymbolInfoTick(_Symbol, tick) == false) return(false);

と同じ意味です。

同じく
if(!RefreshRates()) return;


if(RefreshRates() == false) return;

と同じ意味です。

ここで、return に戻り値がついていないのは、Ontick()void(戻り値なし)として宣言されているからです。

RefreshRates()でレート更新ができなかった場合は、それ以降のプログラムをスキップしてOnTick()関数を終了します。

次にチャートの4本値です。カスタム指標プログラムでは、OnCalculate()関数の引数としてOpen[]、High[]、Low[]、Close[]などの配列が使えたのですが、EAの場合、そのままでは使えません。

EAで4本値を使う方法について、Close[]を例にとって説明します。

まずは、Close[]を外部変数として宣言します。
double Close[];

そして、OnInit()中に、
ArraySetAsSeries(Close, true);

と書き、Close[]を時系列配列(最新のデータがClose[0]、1本前のデータがClose[1]・・・)に設定します。

そして、RefreshRates()関数中に、CopyClose()という関数を使い、終値配列をClose[]配列にコピーします。このCopyClose()関数は、前回CopyBuffer()関数と同じような使い方をします。
CopyClose(_Symbol, _Period, 0, count, Close)

と書くと、挿入したチャートの通貨ペア、タイムフレームにおける終値配列の最新の位置(0)からcount個分をClose[]配列にコピーします。

同様にOpen[]、Low[]、High[]の場合、CopyOpen()、CopyLow()、CopyHigh()という関数を使います。

以下のリストは、countを10とし、10個分の終値を表示させるプログラムです。

double Bid, Ask;
double Close[];

// 初期化関数
int OnInit()
{
ArraySetAsSeries(Close, true);
return(0);
}

// 終了関数
void OnDeinit(const int reason)
{
}

// ティック関数
void OnTick()
{
if(!RefreshRates()) return;
Print("Bid=", Bid);
Print("Ask=", Ask);
for(int i=0; i<10; i++) Print("Close[", i, "]=", Close[i]);
}

// レートの更新
bool RefreshRates()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick)) return(false);
Bid = tick.bid;
Ask = tick.ask;

int count = 10;
if(CopyClose(_Symbol, _Period, 0, count, Close) < count) return(false);
return(true);
}

CopClose()もCopyBuffer()と同様、実際にコピーしたデータの個数を返すので、それがcountより少ない場合、エラーとしてfalseを返しています。

これで、プログラム中で終値をClose[0]、Close[1]などと参照することができるようになりました。

次回はトレードに関する関数について見ていきます。

Posted at 14時58分 パーマリンク


2010年08月24日(火)

MQL5でカスタム指標プログラム(3) [MetaTrader5]

カスタム指標プログラムでテクニカル指標を表示させる最も簡単な方法は、MQL5に既に組み込まれている関数を使うことです。

MQL5にも、MQL4のようによく使うテクニカル指標が組み込み関数として用意されています。例えば、移動平均線を算出する関数はiMA()です。

MQL4では、iMA()などの組み込みテクニカル指標関数は、その指標の値そのものが関数の戻り値だったので、

Buf[i] = iMA(NULL, 0, MAPeriod, 0, MODE_SMA, PRICE_CLOSE, i); 

のように指標バッファ用の配列に直接代入するだけで利用することができました。

しかし、MQL5では、同じiMA()を使うにも、いくつかの手順を踏まなくてはいけません。

まずは、iMA()を利用して移動平均線を表示するMQL5プログラムを示します。


#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

#property indicator_label1 "MA"
#property indicator_type1 DRAW_LINE
#property indicator_color1 Red
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2

// パラメータ
input int MAPeriod = 20;

// 指標バッファ
double Buf[];

// テクニカル指標ハンドル
int hMA;

// 初期化関数
int OnInit()
{
// 指標バッファの割り当て
SetIndexBuffer(0, Buf, INDICATOR_DATA);

// テクニカル指標の初期化
hMA = iMA(NULL, 0, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);

return(0);
}

// 終了関数
void OnDeinit(const int reason)
{
// テクニカル指標の解放
IndicatorRelease(hMA);
}

// 開始関数
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[])
{
// バッファのコピー
CopyBuffer(hMA, 0, 0, rates_total, Buf);
return(rates_total);
}

順に説明していきます。

// パラメータ
input int MAPeriod = 20;

これは、iMA()で利用する「移動平均の期間」を変えるための変数です。チャート挿入時に現れるプロパティ画面のInputsタブ(下図)で値を変えることができます。

画像(450x180)・拡大画像(719x288)

このような用途の場合、MQL4では「extern」をつけて宣言していましたが、MQL5では「input」というキーワードに変わりました。

次に、問題のiMA()の使い方ですが、

// テクニカル指標ハンドル
int hMA;

に注目してください。

テクニカル指標ハンドルとは聞きなれない言葉ですが、MQL5では、外部変数として宣言したハンドルと呼ばれる変数を介してテクニカル指標を扱うようになっているのです。

プログラム中では、「hMA」という変数は以下の3箇所に出てきます。
OnInit()中
// テクニカル指標の初期化
hMA = iMA(NULL, 0, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);

OnDeinit()中
// テクニカル指標の解放
IndicatorRelease(hMA);

OnCalculate()中
// バッファのコピー
CopyBuffer(hMA, 0, 0, rates_total, Buf);

手順としては、まず、OnInit()関数の中でiMA()を呼び出し、テクニカル指標の初期化を行います。

テクニカル指標の初期化とは、プログラム内部に移動平均用の配列を確保し、チャート全体の移動平均の値を格納しておくことです。

iMA()のパラメータはMQL4の場合とほぼ同じです。この例では、挿入したチャート上での終値に対する単純移動平均(SMA)を求めます。

但し、iMA()の戻り値は移動平均の値ではなく、このテクニカル指標を特定するための値(ハンドル)です。

つまり、MQL4のように各バーにおける移動平均の値をいちいちiMA()を呼び出して算出するのではなく、移動平均の値は内部の配列に自動的に算出されるわけです。

この移動平均の入っている配列をそのまま表示すれば簡単なのですが、残念ながらこれを直接表示させることはできず、表示用の指標バッファとして割り当てられた配列にコピーしてやる必要があるのです。

それが、OnCalculate()中のCopyBuffer()という関数で行っていることです。CopyBuffer()では、最初の引数にコピーしたいテクニカル指標のハンドル、2番目の引数にテクニカル指標のインデックス(移動平均の場合、指標は1本しかないので、0を指定)を代入します。

3番目と4番目の引数は変数の型によって意味が違ってくるのですが、両方intの場合、コピーしたいテクニカル指標の位置とコピーしたい個数を指定します。0, rates_total の場合、0の位置からrates_total個の指標データをコピーすることを意味します。

そして、5番目の引数はコピー先の配列名です。ここでは、SetIndexBuffer()で割り当てた「Buf」を指定します。

これで、rates_total個、つまりチャート上のすべての移動平均の値をBuf[]にコピーすることができたわけです。

最後にOnDeinit()(MQL4のdeinit()と同じ)中でIndicatorRelease(hMA)を呼んでいますが、これは、hMAで確保した配列を解放することを意味します。このプログラムが終了すれば、移動平均の配列は不要となるので、メモリの消費を防ぐために解放しておくのです。

以上が組み込みテクニカル指標関数の最も簡単な使い方です。コンパイルしてチャートに挿入すると次のように表示されます。

画像(450x337)・拡大画像(800x600)

但し、このままでは、OnCalculate()を呼ぶ毎にチャート上のすべての移動平均の値をコピーします。新しいバーのために必要な分だけコピーするには、CopyBuffer()でコピーする個数を変えてやる必要があります。

ここで注意することは、Buf[]は、最も古いバーからインデックスが振られている配列なのに対して、hMAで確保されている内部配列は最新のバーから古い方にインデックスが振られている「時系列配列」だということです。

ですから、CopyBuffer()で、0からrates_total個というのは、最新のバーからrates_total個ということになります。そこで、rates_tatalをcountに変えると、最新のバーからcount個のデータをコピーすることになります。

プログラムは次のように追加・修正します。

int limit = prev_calculated; 
if(prev_calculated > 0) limit--;
int count = rates_total-limit;

// バッファのコピー
if(CopyBuffer(hMA, 0, 0, count, Buf) < count) return(0);

前回の記事で説明したlimitという変数を使い、count=rates_total-limit とします。すると、最初はcount=rates_total となり、すべてのデータをコピーしますが、2回目からはcount=1となるので、最新のバーのみのコピーとなります。

なお、ここでif文になっているのは、CopyBuffer()の戻り値が実際にコピーできた指標データの個数になるのですが、それが指定したcountより少ない場合、エラーなので、return(0)として次回の実行時にコピーし直すためです。

簡単な方法と言いながら、ちょっと長くなってしまいました。配列のコピーについては、別の機会にも出てきますので、そのときにまた説明します。

Posted at 16時23分 パーマリンク


過去の記事へ

ページのトップへ ページのトップへ

Sponsor AD

シストレナビモバイル

シストレナビモバイル
ケータイでバーコードを読み取りアクセス(詳細はこちら

プロフィール

豊嶋久道

2003年よりFX取引を始め、システムトレードの道へ。最近ではFXオプション取引も含めたトレーディングシステムの研究を行っている。システムトレードを基礎から正しく理解するための情報を発信する予定。

活動状況・Website

ToyolabFX
Toyolab FX-手ぶらで為替取引
FXトレーディング研究所。
FXメタトレーダー入門
FXメタトレーダー入門
最先端システムトレードソフト使いこなし術。
FXメタトレーダー実践プログラミング
FXメタトレーダー実践プログラミング
システム開発過程を段階的に学ぶ。

2010/9

      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

PHOTO

相場はランダムウォーク?

相場はランダムウォーク?

カテゴリーリスト

最近の記事

スポンサードリンク

検索


当サイトコメントについて

当コメントは情報提供のみを目的として作成されたものであり、投資に関してはご自身でご判断くださいますようお願い致します。また、当資料は著作物であり著作権法により保護されております。無断で全文または一部を転載することはできません。

RSS1.0

[Login]


powered by a-blog
Copyright (C) 2008 PhiConcept,Inc. All rights reserved.