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

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

 

2012年10月01日(月)

MT5で両建てシステム(11)〜起動時に仮想ポジションを復元 [MQL5]



前回、仮想ポジションを使って売買するスクリプトを複数のチャート上で動かして、それぞれのポジションが独立して管理できることを確認しました。

これをEAに組み込む前に、もう一つ注意することがあります。

仮想ポジションが建っているのがEAを起動している間だけであり、EAを起動したときや終了するときに仮想ポジションがない場合、特に問題はありません。

しかし、仮想ポジションがある状態でEAを終了した場合、次にEAを起動したときにそのポジションがある状態にしておかなくては、不都合が生じます。

そのために、EA起動時に、仮想ポジションの有無をチェックして、ポジションがあれば、その情報を復元しておかなくてはいけません。

仮想ポジションは、以前のコラムで紹介したように、ディールの履歴で判別します。

ディールを最新のものから遡っていき、オープンポジションであれば、その情報をポジションの構造体 MyPosに代入します。また先にクローズポジションを見つけたら、その時点でオープンポジションはないということになります。

ここでオープンポジションか、クローズポジションかの判別は、以下のようにします。

マジックナンバー=MAGIC_B かつ、ディールの売買タイプ=買いの場合、オープンポジション
マジックナンバー=MAGIC_B かつ、ディールの売買タイプ=売りの場合、クローズポジション
マジックナンバー=MAGIC_S かつ、ディールの売買タイプ=買いの場合、クローズポジション
マジックナンバー=MAGIC_S かつ、ディールの売買タイプ=売りの場合、オープンポジション

つまり、マジックナンバーの売買情報とディールの売買情報が一致してればオープンポジション、逆であればクローズポジションと考えます。

この仮想ポジションをチェックする関数をInitPosition()として作成し、OnStart()の最初に呼び出します。

長くなりますが、全体のプログラムを掲載します。

#property script_show_inputs

input ulong MAGIC_B = 1000; // 買いポジションのマジックナンバー
input ulong MAGIC_S = 1001; // 売りポジションのマジックナンバー
input string COMMENT = "Script1"; // コメント
input double Lots = 0.1; // 売買ロット数
input ulong Slippage = 20; // スリッページ

// 仮想ポジションの構造体
struct MyPosition
{
ulong ticket;
double lots;
double price;
}
MyPos;

// スタート関数
void OnStart()
{
InitPosition();

int ret = MessageBox("Buy at market", "TradeTest", MB_OKCANCEL);
if(ret == IDOK) OrderSendMarket(ORDER_TYPE_BUY, Lots, COMMENT+"-BuyOpen");

ret = MessageBox("Close at market", "TradeTest", MB_OKCANCEL);
if(ret == IDOK) OrderClose(COMMENT+"-BuyClose");

ret = MessageBox("Sell at market", "TradeTest", MB_OKCANCEL);
if(ret == IDOK) OrderSendMarket(ORDER_TYPE_SELL, Lots, COMMENT+"-SellOpen");

ret = MessageBox("Close at market", "TradeTest", MB_OKCANCEL);
if(ret == IDOK) OrderClose(COMMENT+"-SellClose");
}

// 新規成行注文
bool OrderSendMarket(ENUM_ORDER_TYPE type, double volume, string comment)
{
if(MyPos.lots != 0) return(false);

MqlTradeRequest request={0};
MqlTradeResult result={0};

MqlTick tick;
SymbolInfoTick(_Symbol, tick);

if(type == ORDER_TYPE_BUY)
{
request.magic = MAGIC_B;
request.price = tick.ask;
}
else if(type == ORDER_TYPE_SELL)
{
request.magic = MAGIC_S;
request.price = tick.bid;
}
else return(false);

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = volume;
request.deviation = Slippage;
request.type = type;
request.type_filling = ORDER_FILLING_FOK;
request.comment = comment;

OrderSend(request,result);
if(result.retcode != TRADE_RETCODE_DONE)
{
Print("OrderSendRetCode=", result.retcode);
return(false);
}
MyPos.ticket = result.deal;
MyPos.lots = result.volume;
MyPos.price = result.price;
if(type == ORDER_TYPE_SELL) MyPos.lots = -MyPos.lots;
Comment(MyPos.lots, " lots at ", MyPos.price);
return(true);
}

// ポジションの決済
bool OrderClose(string comment)
{
if(MyPos.lots == 0) return(false);

MqlTradeRequest request={0};
MqlTradeResult result={0};

MqlTick tick;
SymbolInfoTick(_Symbol, tick);

double lots = MyPos.lots;
if(lots > 0)
{
request.type = ORDER_TYPE_SELL;
request.magic = MAGIC_B;
request.price = tick.bid;
}
else if(lots < 0)
{
request.type = ORDER_TYPE_BUY;
request.magic = MAGIC_S;
request.price = tick.ask;
}
else return(true);

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.deviation = Slippage;
request.volume = MathAbs(lots);
request.type_filling = ORDER_FILLING_FOK;
request.comment = comment;

OrderSend(request,result);
if(result.retcode != TRADE_RETCODE_DONE)
{
Print("OrderCloseRetCode=", result.retcode);
return(false);
}
ZeroMemory(MyPos);
Comment("");
return(true);
}

// ポジションの初期化
void InitPosition()
{
HistorySelect(0, TimeCurrent());
ZeroMemory(MyPos);
Comment("");

for(int i=HistoryDealsTotal()-1; i>=0; i--)
{
ulong ticket = HistoryDealGetTicket(i);
if(HistoryDealGetString(ticket, DEAL_SYMBOL) != _Symbol) continue;
long dmagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
ENUM_DEAL_TYPE dtype = (ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket, DEAL_TYPE);
// クローズポジション
if((dtype == DEAL_TYPE_SELL && dmagic == MAGIC_B) ||
(dtype == DEAL_TYPE_BUY && dmagic == MAGIC_S)) break;
// オープンポジション
if((dtype == DEAL_TYPE_BUY && dmagic == MAGIC_B) ||
(dtype == DEAL_TYPE_SELL && dmagic == MAGIC_S))
{
MyPos.ticket = ticket;
MyPos.lots = HistoryDealGetDouble(ticket, DEAL_VOLUME);
if(dtype == DEAL_TYPE_SELL) MyPos.lots = -MyPos.lots;
MyPos.price = HistoryDealGetDouble(ticket, DEAL_PRICE);
Comment(MyPos.lots, " lots at ", MyPos.price);
break;
}
}
}

まず、HistorySelect()で履歴の範囲を指定します。この場合、履歴全部です。

履歴には古い方から0,1,2とインデックスが振ってあるので、最新のHistoryDealsTotal()-1から1ずつ減らしてディールを探していきます。

for文中では、HistoryDealGetTicket(i)でチケット番号を取得し、HistoryDealGetString()でシンボル名HistoryDealGetInteger()でマジックナンバーや売買タイプを取得します。

それで、先ほどの判別方法に従い、クローズポジションであれば、for文を抜けて関数を終了します。

オープンポジションであれば、HistoryDealGetDouble()で売買ロット数や売買価格を取得してMyPosに代入します。ポジションの状態はComment()で表示します。

このプログラムを実行して、例えば、買いポジションだけ建てて、残りのトレードをキャンセルし、終了したとします。この状態で次にプログラムを実行したときに、仮想ポジションとして買いポジションがある状態になっていればOKです。

なお、このプログラムをテストする際に誤動作を防ぐために、OrderSendMarket()の最初に

if(MyPos.lots != 0) return(false);

という文を入れて、既にポジションがあるときにさらにポジションをとらないようにしています。

またOrderClose()には、

if(MyPos.lots == 0) return(false);

を入れて、ポジションがないときに実行されないようにしています。


>>“基礎から学ぶシステムトレード”全記事バックナンバーはこちらから




Posted at 14時19分


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

Sponsor AD

2012/10

  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 31      

プロフィール

豊嶋久道

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

PHOTO

ランダムウォークとランダムトレード(6)

ランダムウォークとランダムトレード(6)

カテゴリーリスト

最近の記事

検索


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

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

RSS1.0

[Login]


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