今回は、MT4のEAサンプルソース(FX用)を公開します。
2023年現在、よく行われる為替介入ですが中々EAでは介入時や介入後の値動きが考慮できていないのが現状です。
はじめに
為替介入時によくある偽介入(瞬間40pipsぐらい下げてすぐ戻す動きのやつ)でストンと下げた所をロングでとっていけるEAでも作ってみよかなという事で作ってみました。
※ただ為替介入の本物にロングエントリーで仕掛けるとやられちゃうのでそこは工夫しました
作ろうと思ったきっかけ
為替介入後はまた為替介入がきたか!?みたいな偽の為替介入の動きが頻発します。
1分足でこんな感じの動きです。裁量で1回は取れたのですが、PC前でずっとチャートに張り付いている状態になったので、EAで何とかできないかという事で作りました。
個人的には満足行くものができたのでサンプルを載せます。もし良ければ自己責任でどうぞ!
EAの仕様
それでは、今回のソースコードのエントリー/決済/パラメータ設定についての仕様を説明します。
エントリータイミング
ロングエントリー
前回のローソク足の終わり値から、現在の値段が設定の『Entry_Pips』以上下げた場合エントリーします。
例)1分前の終値が145.500なのに今の値が145.000だったらロングエントリー
あと、これは最近2回の為替介入からは判断したのですが、当日150pips以上上げている場合に為替介入しているため、当日150pips以上上げている場合はエントリーしません。
ショートエントリー
ショートエントリーはしません。
エントリー例
私がよく作っているローソク足が確定したらエントリーする形ではなく、常に値動きを監視するタイプでEntry_Pips』以上下げた場合はロングエントリーします。また、エントリー時にTP(指値)とSL(逆指値)を設定しているので決済はそれ任せです。
決済タイミング
今回は決済処理は無く、TP(指値)とSL(逆指値)のみで管理しています。
その他の仕様
このEAは米ドル円の1分足で動かして確認しました。
設定値は以下の通りです。
- MagicNumber= 77777 ⇒ マジックナンバーです
- LotSize= 0.01 ⇒ ロット数です(0.01=1000通貨)
- Entry_Spread= 20 ⇒ エントリー時に許容するスプレッドの値です(20 = 2pips)
- Close_Spread= 20 ⇒ 決済時に許容するスプレッドの値です(20 = 2pips)
- Entry_Pips= 420 ⇒ 瞬間何pips下げた場合エントリーするかの値です(420=42pips)
- Order_TP= 420 ⇒ ストップロスまでのポイントです(1000=100pips)
- Order_SL= 900 ⇒ ストップロスまでのポイントです(1000=100pips)
保持するポジションは最大1つです。
エントリー後、10分間は次のエントリーをしません。(速攻でTPやSL食らったら追加でエントリーしていたのでしないようにしました)
EAレポート結果
為替介入1回目があった2022年9月23日の前の日から2回目があった2022年10月21日までの結果です。
件数は8件と少ないですが、自分が思った通りのEAができました。
1トレード目(唯一の負けトレード)
最初速攻やられてますが、実はこれ為替介入前の動きです。ロシア絡みで介入よりも前に大きく上げ下げしたんだったかな。なのでノーカウントという事で・・・。
2,3トレード目
取り合えずここの1つ目は裁量で運よく取れたのでここをイメージして作りました。ここベースでエントリーpipsの設定値やらTPとSLの設定値を決めています。
4、5トレード目
こちらもうまく入れています。
本物の為替介入時
ここは10月21日の2回目の為替介入時の時ですが、この日だけで150pips以上上げていたのでエントリーしてません。(うまくフィルターが機能した形です)
ダウンロード
上記のEAファイルになります。
“偽介入察知EA” をダウンロード 19_NiseKainyu.ex4 – 862 回のダウンロード – 11.81 KBソースコード
以下サンプルソースコードになります。
※丸々コピペでコンパイルできます
//+------------------------------------------------------------------+
//| NiseKainyu.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
extern string p01="--- Settings ---";
input int MagicNumber = 77777;
input double LotSize = 1;
input int Entry_Spread = 20; //エントリー時の許容スプレッド
input int Close_Spread = 20; //決済時及び監視する許容スプレッド
input double Entry_Pips = 420;
input double Order_TP = 420;
input double Order_SL = 900;
int Main_ea_ticket[2]; //ポジションのチケット番号保有用(2だと3ポジまで) 5ポジ持たせたい場合は4にすること
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
int start()
{
//---
int OrderKekka;
int orderPtn = 0;
double ea_order_stop_price,ea_order_good_price;
//前回1分足の値を取得する
double rosokuValueCloseP = iClose(NULL, 0, 1);
//その日の高値、始値を取得する
double rosokuValueHighD = iHigh(NULL, PERIOD_D1, 0);
double rosokuValueOpenD = iOpen(NULL, PERIOD_D1, 0);
//Entry_Pips分急激に下げた場合
if(Bid <= rosokuValueCloseP - Entry_Pips * Point){
//当日既に150pips以上あがっていたら介入かもしれないのでエントリーしない
if(rosokuValueHighD >= rosokuValueOpenD + 1500 * Point){
Print("介入警戒:",rosokuValueHighD,">=",rosokuValueOpenD + 1500 * Point);
orderPtn = 0;
}else{
orderPtn = 1;
ea_order_stop_price = Bid - Order_SL * Point;
ea_order_good_price = Bid + Order_TP * Point ;
}
}
if(funcOrder_Select(1,0,MagicNumber,Main_ea_ticket) == true)
{
//10分以内にトレードした場合は様子見
if(OrderCloseTime() > iTime(NULL, 0, 10)){
orderPtn = 0;
}
}
if(orderPtn > 0)
{
//新規注文
OrderKekka = funcOrder_Send(Entry_Spread,0,orderPtn - 1,ea_order_stop_price,ea_order_good_price,"",MagicNumber,LotSize);
}
return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|【関数】オーダーセレクト関数
//|
//|【引数】 mode 0:最新ポジション選択(ポジション数も取得) 1:1つ前の決済ポジ 2:2つ前の決済ポジ ・・・
//|【引数】 ticket 0:チケット番号を選択したい場合チケット番号を渡すと保持してくれる
//|【引数】 マジックナンバー
//|【引数(参照)】 mode 0の場合、最新のチケット番号群を更新する
//|
//|【戻値】ポジション数(過去の場合はあったINDEX)
//|
int funcOrder_Select(int mode,int ticket,int ea_order_MagicNo,int &o_Ticket[2]){
int total=0,cnt=0,ticket_buf=0;
bool OrderKekka =false;
total = 0;
if(mode==0){
//チケット配列のクリア
for(int i = 0;i<3;i++){
o_Ticket[i]=0;
}
for(cnt = 0; cnt < OrdersTotal(); cnt++){
if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES) == true){
if(OrderMagicNumber() == ea_order_MagicNo){
o_Ticket[total] = OrderTicket();
ticket_buf = OrderTicket();
total = total+1;
}
}
}
//件数が会った場合、最新のポジションを選択する
if(ticket == 0 && ticket_buf !=0){
OrderKekka = OrderSelect(ticket_buf,SELECT_BY_TICKET,MODE_TRADES);
}
//チケット番号が渡されている場合戻す
if(ticket != 0){
OrderKekka = OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
}
}else{
for(cnt = OrdersHistoryTotal(); cnt > 0; cnt--){
if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){
if(OrderMagicNumber() == ea_order_MagicNo){
total = total+1;
if(mode <= total){
break;
}
}
}
}
}
return(total);
}
//+------------------------------------------------------------------+
//|【関数】新規注文関数
//|
//|【引数】 EntrySpread:エントリー時の許容スプレッド
//|【引数】 ea_order_ryoudate:両建て有無(0:無 1:有)
//|【引数】 ea_order_entry_Type:売買(0:買 1:売)
//|【引数】 order_stop_price:損切値 order_good_price:利確値
//|【引数】 orderComment:オーダーコメント ea_order_MagicNo:マジックNo
//|
//|【戻値】True:成功 False:失敗
//|
//|
bool funcOrder_Send(int EntrySpread, int ea_order_ryoudate, int ea_order_entry_Type, double order_stop_price, double order_good_price,string orderComment,int ea_order_MagicNo,double Lots)
{
int order_resend_num,ea_ticket_res; // エントリー試行回数,チケットNo
double ea_order_entry_price; // エントリーレート
color order_Color;
bool kekka;
int ea_ticket[2]; //ポジションのチケット番号保有用(2だと3ポジまで) 5ポジ持たせたい場合は4にすること
kekka=false;
int total = funcOrder_Select(0,0,ea_order_MagicNo,ea_ticket);
if(total > 0){
if(ea_order_entry_Type==0 && OrderType() == OP_BUY){
//ポジション保持中
return kekka;
}
else if(ea_order_entry_Type==1 && OrderType() == OP_SELL){
//ポジション保持中
return kekka;
}
if(ea_order_ryoudate == 0){
return kekka;
}
}
for( order_resend_num = 0; order_resend_num < 3; order_resend_num++ ) { // エントリー試行回数上限:3回
//スプレッドが1銭未満の場合のみ新規注文する(2銭未満にしたい場合は20にする)
if(MarketInfo(NULL,MODE_SPREAD) <= EntrySpread){
if(ea_order_entry_Type == OP_BUY){
ea_order_entry_price = Ask; // 現在の買値でエントリー
order_Color = clrBlue;
}else if(ea_order_entry_Type == OP_SELL){
ea_order_entry_price = Bid; // 現在の売値でエントリー
order_Color = clrRed;
}
if(orderComment == 25){
order_Color = clrGreenYellow;
}
// FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
ea_ticket_res = OrderSend( // 新規エントリー注文
NULL, // 通貨ペア
ea_order_entry_Type, // オーダータイプ[OP_BUY / OP_SELL]
Lots, // ロット[0.01単位](FXTFは1=10Lot)
ea_order_entry_price, // オーダープライスレート
20, // スリップ上限 (int)[分解能 0.1pips]
order_stop_price, // ストップレート
order_good_price, // リミットレート
orderComment, // オーダーコメント
ea_order_MagicNo, // マジックナンバー(識別用)
0, // オーダーリミット時間
order_Color // オーダーアイコンカラー
);
if ( ea_ticket_res == -1) {
Print("新規注文失敗 エラーNo:",GetLastError()," リトライ回数:",order_resend_num+1);
Sleep(1000); // msec待ち
RefreshRates(); // レート更新
} else { // 注文約定
Print("新規注文完了 レート:",ea_order_entry_price," ロット数:",Lots," オーダーコメント:",orderComment);
Sleep(500); // 500msec待ち
kekka=true;
break;
}
}else{
Print("スプレッド拡大中(銭)=",MarketInfo(NULL,MODE_SPREAD) / 10," リトライ回数=",order_resend_num+1);
Sleep(5000); // msec待ち
RefreshRates(); // レート更新
}
}
return kekka;
}
さいごに
以上、偽為替介入を察知するサンプルソースでした。
為替介入の偽をロングで取り、為替介入の本物は回避したいという思いで作りました。しばらくは0.01で様子見しながら動かしていこうと思います。
※ EAのサンプルソースを一覧表にまとめました
※EA作成依頼はこちら
※オンラインレッスンやってます
コメント
為替介入の為だけでは、使い道が無いので、口座情報を付けると使えるかな?
と思いました。