今回は、画面上のPIPS消去による決済機能です。
まずは、MQL4のソースをそのままインプリメントします。
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 32 33 34 |
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long & lparam, const double & dparam, const string & sparam) { AppWindow.ChartEvent(id, lparam, dparam, sparam); if((id == CHARTEVENT_OBJECT_DELETE) // オブジェクトが削除された && (input_DelClose)) //PIP表示削除で決済 { if(StringFind(sparam, Str_dsppip) == 0) { //オーダー番号を切り出す string sep_str[]; StringSplit(sparam, '_', sep_str); //バッファの2個目にはオーダー番号 int norderno = StrToInteger(sep_str[1]); if(!OrderSelect(norderno, SELECT_BY_TICKET, MODE_TRADES)) { Print("OrderSelect失敗 オーダーNo=", norderno); return; } //決済処理 if(!OrderClose(norderno, OrderLots(), OrderClosePrice(), 0)) { Print("OrderClose失敗 オーダーNo=", norderno); return; } // PlaySound("Ok.wav"); } } } |
エラーは以下の通り
MQL4 | MQL5 | |
int StrToInteger(string value) | long StringToInteger(string value) | StrToInteger 値文字表記を含むストリングをint (整数)タイプに変換します。 StringToInteger |
簡単簡単。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { AppWindow.ChartEvent(id, lparam, dparam, sparam); if((id == CHARTEVENT_OBJECT_DELETE) // オブジェクトが削除された && (input_DelClose)) //PIP表示削除で決済 { Print(__FUNCTION__, "id=", id, " sparam=", sparam); if(StringFind(sparam, Str_dsppip) == 0) { //チケット番号(バッファの2個目)を切り出す string sep_str[]; StringSplit(sparam, '_', sep_str); ExitCurrency.exitbyorderno(StringToInteger(sep_str[1])); } } } |
新規にチケット番号クローズを追加
MQL4の場合は、ピンポイントで
クローズできたのだが
ポジション数分ループさせ
チケット番号と一致しているものを
クローズする。
さらに非同期のため
確実にクローズが終わるまで回す。
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 32 33 34 35 36 37 38 39 40 41 |
//+------------------------------------------------------------------+ //|指定のチケット番号のポジションをクローズする | //+------------------------------------------------------------------+ bool CExitCurrency::exitbyorderno(long orderno) // --- 4 { CTrade ExtTrade; Print(__FUNCTION__, " orderno =", orderno); int leftcount = 0; //現通貨の残り個数 for(int s = 0; s < 10; s++) { leftcount = 0; //現通貨の残り個数 int ncount = PositionsTotal(); Print(s, "回目め 残り回数 -> ", ncount); for(int i = 0; i < ncount; i++) { PositionGetTicket(i); if(PositionGetInteger(POSITION_TICKET) == orderno) { leftcount++; if(! ExtTrade.PositionClose(_Symbol)) { Print("PositionClose失敗"); } Print("ResultRetcode -> ", ExtTrade.ResultRetcode()); break; } } if(!leftcount) //現通貨がなかったらループを抜ける break; Sleep(250); } return true; } |
できたー
と思いきや。
PIPS整理ですべてクローズされてしまう。
一旦、画面のPIPSを削除するため
クローズ処理が走ってしまうのだ。
あれ、MQL4のときは?
と思ってMQL4のログを見ると
* ワイルドカードになっている。
その結果、IDと一致しないので
クローズされないのだ。
MQL5の場合は、すべてのIDが入ってくるので
すべてクローズ処理が走ってしまう。
やり方としては2つ
- PIPS整理でPIPSを消さずに整理する
- PIPS整理時フラグを立て、フラグが立っているときはクローズしない
1.実は面倒くさい。
単純にアクティブなポジションを整理するだけならいいが、
クローズされたボジションを消すすべがない。
やるとすれば、現在のポジションを管理する
テーブル的なものを作り、クローズポジションを
把握する必要がある。
2.フラグ作戦は、簡単にできるが。。。ダサい
(プログラミングにおいてフラグを使うのはバグの元であり、最後の手段)
それにオフするタイミングがわからない
というか、複数プロコンが動いていると
おそらくうまくいかないタイミングがでる
とはいえ、右クリックして削除するまでに
1秒以上かかるので、1秒後にフラグをOFFでいいかも。
できました。
まずフラグの追加
1 |
bool berasepips; //PIPS整理中フラグ |
セッターとゲッター
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
bool GetErasePips(void); //PIPS整理フラグの取得 void SetErasePips(bool bval); //PIPS整理フラグの設定 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CPanelDialog::GetErasePips(void) { return(berasepips); //PIPS整理中フラグ } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CPanelDialog::SetErasePips(bool bval) { berasepips = bval; //PIPS整理中フラグの設定 } |
PIPS整理処理でフラグの設定
1 2 3 4 5 6 7 8 9 10 |
//+------------------------------------------------------------------+ //|画面上のPIPS表示を消去する | //+------------------------------------------------------------------+ void CPanelDialog::OnClickPipsErase(void) { // ObjectsDeleteAll(0,m_dsppips);// m_dsppips ←const string Str_dsppip = "dsppi_"; //ユニークにするための文字列 ErasePipsDsp(); SetErasePips(1); //ExitCurrency.ClearExitTotalPips();//決算済みPIPSのクリア } |
OnTick()の一番最後(PIPS表示完了後)にフラグをオフ
1 |
AppWindow.SetErasePips(0); //PIPS整理中フラグをオフる |
イベント処理にフラグの判別処理を追加
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 32 |
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { AppWindow.ChartEvent(id, lparam, dparam, sparam); if(AppWindow.GetErasePips()) return; //PIPS整理中は無視する if((id == CHARTEVENT_OBJECT_DELETE) // オブジェクトが削除された && (input_DelClose)) //PIP表示削除で決済 { Print(__FUNCTION__, "id=", id, " sparam=", sparam, " GetErasePips()=", AppWindow.GetErasePips()); if(StringFind(sparam, Str_dsppip) == 0) { //チケット番号(バッファの2個目)を切り出す string sep_str[]; StringSplit(sparam, '_', sep_str); ExitCurrency.exitbyorderno(StringToInteger(sep_str[1])); } } } |
完了です。
とおもいきや、
1個の削除で、複数クローズしてしまう
なるほど、一つ削除すると
チケット番号が塗り替わるのだ。
266350396を削除しても
また、266350396が出現するので
結局全てのポジションを削除してしまう。
うーん、力技で行きます。
1回めに残り個数を保持し
2回め以降に数が減っていれば、メインループを抜ける
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//+------------------------------------------------------------------+ //|指定のチケット番号のポジションをクローズする | //+------------------------------------------------------------------+ bool CExitCurrency::exitbyorderno(long orderno) // --- 4 { CTrade ExtTrade; Print(__FUNCTION__, " orderno =", orderno); int ntotalpos = 0; //トータルポジション数 for(int s = 0; s < 10; s++) { int ncount = PositionsTotal(); Print(s, "回目め 残り回数 -> ", ncount," 1回目のポジション数=",ntotalpos); if(s > 0) //2回め以降のとき { if(ntotalpos > ncount) //ポジションの数が減っていたら break;//終了 } else { ntotalpos = ncount; //クローズ前の個数を保持しておく } for(int i = 0; i < ncount; i++) { PositionGetTicket(i); Print("PositionGetInteger(POSITION_TICKET) =", PositionGetInteger(POSITION_TICKET)); if(PositionGetInteger(POSITION_TICKET) == orderno) { if(! ExtTrade.PositionClose(_Symbol)) { Print("PositionClose失敗"); } Print("ResultRetcode -> ", ExtTrade.ResultRetcode()); break; } } Sleep(250); } return true; }か |
ログを確認。
いい感じです。
完成!
MQL4では、
1 |
OrderClose(norderno, OrderLots(), OrderClosePrice(), 0) |
これだけの処理が、
非同期になったためにこれだけ冗長に
なってしまった。
MQL4のOrderClose()をMQL5への置き換えする際のポイント
- 非同期なので、何度かチェックする必要がある
- クローズが成功すると、使用していたチケット番号が再利用される
一つずれて決済される
できたと思って、決済したら
なぜだか一つずれて決済されていた。
1 2 3 |
if(PositionGetInteger(POSITION_TICKET) == orderno) { if(! ExtTrade.PositionClose(orderno))こ |
これがいけないらしい。
うーーーーーーーーーーーーーん。
再度仕様を見ると。
PositionClose
指定されたシンボルでポジションを決済します。
bool PositionClose( |
Closes a position with the specified ticket.
bool PositionClose( |
あれ?
引数にチケットを指定すればいいだけじゃね?
というわけで、これだけでOKでした。
1 |
ExtTrade.PositionClose(orderno) |
一応、非同期なのでできるのを
確認できるまでぐるぐる回します。
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 32 33 34 35 36 37 38 39 40 |
//+------------------------------------------------------------------+ //|指定のチケット番号のポジションをクローズする | //+------------------------------------------------------------------+ bool CExitCurrency::exitbyorderno(long orderno) // --- 4 { CTrade ExtTrade; Print(__FUNCTION__, " orderno =", orderno); int ntotalpos = 0; //トータルポジション数 for(int s = 0; s < 10; s++) { int ncount = PositionsTotal(); Print(s, "回目め 残り回数 -> ", ncount, " 1回目のポジション数=", ntotalpos); if(s > 0) //2回め以降のとき { if(ntotalpos > ncount) //ポジションの数が減っていたら break;//終了 } else { ntotalpos = ncount; //クローズ前の個数を保持しておく } if(! ExtTrade.PositionClose(orderno)) { Print("PositionClose失敗"); } Print("ResultRetcode -> ", ExtTrade.ResultRetcode()); Sleep(250); } return true; } |
つぎはこちら