昔作ったEA(FX自動売買)のソースコードを無料公開

4児パパ

こんばんは4児パパです。

 

昔すごーくはまってEAの開発を行っていた。

 

元々は職場の先輩からFXをすすめられ、買ったり売ったりをぽちぽちぽちぽちしていたんだけれども、どうにもセンスがなく、「こんなにセンスがないならいっそ自動化してロボットに任せた方が勝てるんじゃないか」と思って「自動売買 FX」で検索してEA(自動売買ツール)を知った。

そして値段の高さに驚愕した。

「3万て。。。ウソやん」

自分の認識というか物の価値をわかっていないというか、EAってそれくらいして当然のものばかりなのだがとにかく、僕にはとてもとても手が出ない金額だった。

だから無料のを探した。もういろいろ検索しまくってしまくってしまくって…いくつか見つけた。

みつけたのでもちろん使ってみようと思ったが、やはり今後の将来をそのソフトに託すのである(言いすぎだけど本当に託すつもりだった←バカと欲丸出し)。バックテストをしてみた

*バックテスト➡為替が実際の過去の値動きをした場合のそのEAが生み出す損益を知ることができるシミュレーション

んで大敗。もちろんシミュレーションなのでこれから先はどうなるか分からない。だが考えてみてほしい。過去にぼろ負けするソフトに将来を託せるか←まだ言ってる

そりゃまぁ無料で勝てるソフトあったら有料のソフトなんていらんわな。ただそれを買う金がない。ならばどうするっ!そうだ!作ればいい!!←唐突

と、まぁそんな感じでEAの開発をすることにした。

自慢じゃないが僕はエクセルは多少できたがプログラミングなんてしたことがまったくない。

だから本当に苦労した。寝るまも惜しんで毎日毎日毎日毎日プログラム言語とにらめっこ。

深夜3時までにらめっこして朝6時には起床する生活を3か月ほど毎日行ったらEAを自力で作成できるようになった(人間てやればできるんだなって本気で思った)

そっから自分の考えたロジックを言語化するという作業を来る日も来る日も行っていくのだが、細かい没EAをふくめたらもしかしたら50くらいつくったかもしれない。

そうしてできあがった満足のいくEAだったが結局もとになるお金がなさすぎでそのEAで運用しても全然お金が増えない。

こりゃある程度元金がねぇとFXなんて無理だべ。

次なる目標が決まった。EAを売ろう←また唐突

ゴゴジャンってサイトに登録して販売もしたりしてみたがやはりなかなか買われなくて。。。

そんなこんなしているうちにプライベートで色々変化があってEA弄る暇がなくなって熱意もなくなって最終的にもう全然忘れ去られたEAがここにあるっ

以下注意点

①いかなる場合も責任おいません。必ず動作チェックしてね

②いかなる場合も責任負いません←大事なことなのでもう一度。

③結構昔のなのでちゃんと動かないかも

④使ってもいいし好きに編集してもいいけどまんま販売するとかやめてね

⑤ソースコードをコンパイルして使ってね

//+———————————————————————+
// パラメーター設定
//+———————————————————————+
extern int MAGIC1 = 12345;//マジックナンバー
extern double BaseLots1=0.01;//MAGIC1 トリヒ キロット
extern double SLATR1x=0;//MAGIC1 ストップロス ATRバイリツ 0=DISUSE
extern double TPATR1x=0;//MAGIC1 テイクプロフィット ATRバイリツ 0=DISUSE
extern double SLPIPS1x=1;//MAGIC1 ストップロス PIPSシテイ 0=DISUSE
extern double TPPIPS1x=1;//MAGIC1 テイクプロフィット PIPSシテイ 0=DISUSE
extern int BreakEvenMagic1=0;//USE=1 DISUSE=0
extern double evenATRx1=0;//MAGIC1 ブレークイーブン or トレーリングスタートライン ATRバイリツ 0=DISUSE
extern double evenPIPSx1=0;//MAGIC1 ブレークイーブン or トレーリングスタートライン PIPSシテイ 0=DISUSE
extern int TrailingStopMagic1=0;//USE=1 DISUSE=0 ブレークイーブン ト ヘイヨウ
extern double TrailingATRx1=0;//MAGIC1 トレーリングストップ ATRバイリツ 0=DISUSEextern int Slippage=5;//キョヨウ スリッページ
extern int WeekendDay=5;//シュウマツ 5=キンヨウビ 6=ドヨウビ゙
extern string WeekendStartTime=”23:00″;//シュウマツ キンシジカン スタートジカン//+———————————————————————+

//その他項目

double Lots1;

double evenpips=0.5;

int ATRpoint=9;
int MaxPosition=1;//サイダイ ポジション

//+———————————————————————+
// 一般関数
//+———————————————————————+

double AdjustPoint(string Currency)//ポイント調整
{
int Symbol_Digits=MarketInfo(Currency,MODE_DIGITS);
double Calculated_Point=0;
if (Symbol_Digits==2 || Symbol_Digits==3)
{
Calculated_Point=0.01;
}
else if (Symbol_Digits==4 || Symbol_Digits==5)
{
Calculated_Point=0.0001;
}
return(Calculated_Point);
}

double AdjustSlippage(string Currency,int Slippage_pips )//スリッページ調整
{
double Calculated_Slippage;
int Symbol_Digits=MarketInfo(Currency,MODE_DIGITS);
if (Symbol_Digits==2 || Symbol_Digits==3)
{
Calculated_Slippage=Slippage_pips;
}
else if (Symbol_Digits==4 || Symbol_Digits==5)
{
Calculated_Slippage=Slippage_pips*10;
}
return(Calculated_Slippage);
}

int LongPosition(int MAGIC)//ロングポジション数を取得
{
int buys=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_BUY) buys++;
}
}
return(buys);
}

int ShortPosition(int MAGIC)//ショートポジション数を取得
{
int sells=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_SELL) sells++;
}
}
return(sells);
}

//エントリ可能時間帯かどうかを確認
int IsEntryTimeCheck(bool IsAllow ,string stime,string etime)// IsAllow_ture-当該時間の許可確認,false_禁止確認
{
int ret=0;
string startdate = TimeToStr(TimeCurrent(), TIME_DATE);
datetime start_time = StrToTime(startdate +” ” + stime);
datetime end_time = StrToTime(startdate +” ” + etime);
if( stime < etime )
{
if( TimeCurrent() >= start_time && TimeCurrent() < end_time ) ret = true;
else ret = -1;
}
else
{
if( TimeCurrent() >= end_time && TimeCurrent() < start_time ) ret = false;
else ret = 1;
}
if( IsAllow == false ) ret = ret*-1;
return(ret);
}

//週末決済時間を超えているかを確認
int IsWeekend()
{
int ret=1;
int weekday = DayOfWeek();
if (weekday == 6 && WeekendDay==5)
{
ret=-1;
}
else if(weekday == WeekendDay)
{
if (IsEntryTimeCheck(false,WeekendStartTime,”23:59″)==-1) ret=-1;
}
else if(weekday == 5 && WeekendDay==6) ret=1;
return(ret);//-1は停止時間、1は稼働時間
}

//+———————————————————————+
// エントリ関連関数
//+———————————————————————+

//ポジションエントリ関数
void OpenOrder(int EntryPosition)
{
int res;
int SLP=AdjustSlippage(Symbol(),Slippage );

//ロットサイズ調整
Lots1=BaseLots1;//固定ロット

if( EntryPosition == -1) //エントリ条件
{
res=OrderSend(Symbol(),OP_SELL,Lots1,Bid,SLP,0,0,NULL,MAGIC1,0,Blue);
}
if( EntryPosition == 1) //エントリ条件
{
res=OrderSend(Symbol(),OP_BUY,Lots1,Ask,SLP,0,0,NULL,MAGIC1,0,Red);
}

return;
}

//+———————————————————————+
// エグジット関連関数
//+———————————————————————+

//ポジションクローズ関数
void CloseOrder(int ClosePosition,int MAGIC)
{
for(int i=OrdersTotal()-1;i>=0;i–)
{
int res;
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true)
{
if(OrderMagicNumber()==MAGIC && OrderSymbol()==Symbol())
{
if(OrderType()==OP_SELL && ClosePosition!=1) //売りポジションのクローズ
{
res=OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),10,Silver);
}
else if(OrderType()==OP_BUY && ClosePosition!=-1) //買いポジションのクローズ
{
res=OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),10,Silver);
}
}
}
}
}

//ブレークイーブンストップ関数
void BreakEvenStop(double evenA,double evenP,int MAGIC)
{
int res;
double Pips_Profit;
double Min_Profit;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_BUY && evenA!=0)
{
Pips_Profit=Bid-OrderOpenPrice();
Min_Profit=evenA*iATR(NULL,0,ATRpoint,1);
if (Pips_Profit>=Min_Profit && OrderStopLoss()==0)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+evenpips*AdjustPoint(Symbol()),OrderTakeProfit(),0,Orange);
}
}
if(OrderType()==OP_BUY && evenP!=0)
{
Pips_Profit=Bid-OrderOpenPrice();
Min_Profit=evenP*AdjustPoint(Symbol());
if (Pips_Profit>=Min_Profit && OrderStopLoss()==0)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+evenpips*AdjustPoint(Symbol()),OrderTakeProfit(),0,Orange);
}
}
if(OrderType()==OP_SELL && evenA!=0)
{
Pips_Profit=OrderOpenPrice()-Ask;
Min_Profit=evenA*iATR(NULL,0,ATRpoint,1);
if (Pips_Profit>=Min_Profit && OrderStopLoss()==0)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-evenpips*AdjustPoint(Symbol()),OrderTakeProfit(),0,Orange);
}
}
else if(OrderType()==OP_SELL && evenP!=0)
{
Pips_Profit=OrderOpenPrice()-Ask;
Min_Profit=evenP*AdjustPoint(Symbol());
if (Pips_Profit>=Min_Profit && OrderStopLoss()==0)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-evenpips*AdjustPoint(Symbol()),OrderTakeProfit(),0,Orange);
}
}
}
}
}

//トレーリングストップ関数
void TrailingStop(double TrA,int MAGIC)
{
double new_sl;
int res;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_BUY && OrderOpenPrice()+(TrA*iATR(NULL,0,ATRpoint,1))<Bid && OrderStopLoss()<Bid)
{
new_sl = Bid-(TrA*iATR(NULL,0,ATRpoint,1));
if(OrderStopLoss()!=0 && new_sl > OrderStopLoss()+1*Point)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),new_sl,OrderTakeProfit(),0,clrNONE);
}
}
else if(OrderType()==OP_SELL && OrderOpenPrice()-(TrA*iATR(NULL,0,ATRpoint,1))>Ask && (OrderStopLoss()>Ask || OrderStopLoss()==0) )
{
new_sl = Ask+(TrA*iATR(NULL,0,ATRpoint,1));
if(OrderStopLoss()!=0 && new_sl < OrderStopLoss()-1*Point)
{
res=OrderModify(OrderTicket(),OrderOpenPrice(),new_sl,OrderTakeProfit(),0,clrNONE);
}
}
}
}
}

//+———————————————————————+
//  インジケーター
//+———————————————————————+

//5-2 ボリンジャーバンドタッチ
int Indicator()
{
{
int ret=0;
if(High[1]-Close[1]>0.1*AdjustPoint(Symbol())){ret=1;}
if(Close[1]-Low[1]>0.1*AdjustPoint(Symbol())){ret=-1;}
}
return(ret);
}

//5-2 利益確定クローズ
int TPCLOSE(int MAGIC,double TPATR,double TPPIPS)
{
int ret=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_BUY && TPATR!=0)
{
if(OrderOpenPrice()+(TPATR*iATR(NULL,0,6,1))<Bid){ret=1;}
}
if(OrderType()==OP_BUY && TPPIPS!=0)
{
if(OrderOpenPrice()+(TPPIPS*AdjustPoint(Symbol()))<Bid){ret=1;}
}
if(OrderType()==OP_SELL && TPATR!=0)
{
if(OrderOpenPrice()-(TPATR*iATR(NULL,0,6,1))>Ask){ret=-1;}
}
else if(OrderType()==OP_SELL && TPPIPS!=0)
{
if(OrderOpenPrice()-(TPPIPS*AdjustPoint(Symbol()))>Ask){ret=-1;}
}
}
}
return(ret);
}

//5-2 損切クローズ)
int SLCLOSE(int MAGIC,double SLATR,double SLPIPS)
{
int ret=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
{
if(OrderType()==OP_BUY && SLATR!=0)
{
if(OrderOpenPrice()-(SLATR*iATR(NULL,0,6,1))>Bid){ret=1;}
}
if(OrderType()==OP_BUY && SLPIPS!=0)
{
if(OrderOpenPrice()-(SLPIPS*AdjustPoint(Symbol()))>Bid){ret=1;}
}
if(OrderType()==OP_SELL && SLATR!=0)
{
if(OrderOpenPrice()+(SLATR*iATR(NULL,0,6,1))<Ask){ret=-1;}
}
else if(OrderType()==OP_SELL && SLPIPS!=0)
{
if(OrderOpenPrice()+(SLPIPS*AdjustPoint(Symbol()))<Ask){ret=-1;}
}
}
}
return(ret);
}

//+———————————————————————+
// ティック毎の処理
//+———————————————————————+
void start()
{

//週末持ち越し停止
int W=1;
if(IsWeekend()==-1)
{
CloseOrder(0,MAGIC1);
W=-1;
}

//ブレークイーブン
if(BreakEvenMagic1==1)
{
static bool checkDone;
int sec = TimeSeconds(TimeGMT());
if(sec == 0 || sec == 30 )
{
if(checkDone==false)
{
if(BreakEvenMagic1==1)
{
BreakEvenStop(evenATRx1,evenPIPSx1,MAGIC1);
}
}
}
else
{
checkDone = false;
}
}

//トレーリングストップ
if(TrailingStopMagic1==1 )
{
static bool checkDone2;
int sec2 = TimeSeconds(TimeGMT());
if(sec2 == 0 || sec2 == 30 )
{
if(checkDone2==false)
{
if(TrailingStopMagic1==1)
{
TrailingStop(TrailingATRx1,MAGIC1);
}
}
}
else
{
checkDone2 = false;
}
}

//各種パラメーター取得
int EntryBuy=0;
int EntrySell=0;
int ExitBuyA=0;
int ExitSellA=0;
int LongNumA=LongPosition(MAGIC1);
int ShortNumA=ShortPosition(MAGIC1);

//クローズ基準取得
//クローズ判定
//クローズ処理
int CloseStrtagyB2=TPCLOSE(MAGIC1,TPATR1x,TPPIPS1x);
int CloseStrtagyB3=SLCLOSE(MAGIC1,SLATR1x,SLPIPS1x);
//クローズ判定
if(LongNumA!=0 && (CloseStrtagyB2==1 || CloseStrtagyB3==1) )
{
ExitBuyA=1;
LongNumA=0;
}
else
if(ShortNumA!=0 && (CloseStrtagyB2==-1 || CloseStrtagyB3==-1) )
{
ExitSellA=1;
ShortNumA=0;
}

if(ExitBuyA!=0)
{
CloseOrder(1,MAGIC1);
}
if(ExitSellA!=0)
{
CloseOrder(-1,MAGIC1);
}

static datetime time = Time[0];
if(Time[0] != time)
{

//エントリ基準取得
int Strtagy1=Indicator();
int TotalNum=ShortNumA+LongNumA;
int ANum=ShortNumA+LongNumA;

//エントリ判定
if((ANum==0 && W==1 ) && (Strtagy1==1 ))
{
EntryBuy=1;
}
if((ANum==0 && W==1 ) && (Strtagy1==-1 ))
{
EntrySell=1;
}
//オープン処理

if(EntryBuy==1)
{
OpenOrder(1);
}
if(EntrySell==1)
{
OpenOrder(-1);
}
time = Time[0];
}

}

 

 

↓以下こんなEAっていう説明(昔書いてた説明文をまんま載せます(手抜き))↓

ドル円、4時間足での稼働を推奨しております。

最低ロット「0.01」×2ポジでの運用の場合の推奨証拠金は、1ドル110円の場合

8800円+最大ドローダウン7000円=16000円が推奨証拠金になります。

ロジックは、ボリンジャーバンドの収束を察知し、バンドブレイクをした方向にエントリーというブレイクアウト手法になります。

*ある程度伸びてからの順張りエントリーになります。

その際長期RSIでトレンドを把握し、強いトレンドが出ている場合、トレンドと反対方向のエントリーはしないようにしております。

 

取引の流れとしては(初期設定の場合)

①  ボリンジャーバンドの収縮からのブレイクアウト

②  二つのポジションを同時に持つ

③  MAGIC1が利益確定

④  MAGIC2のブレークイーブンが発動

④‐2  もしここで更にブレークアウトを察知するとMAGIC1がエントリー

⑤  MAGIC2およびMAGIC1が決済

のサイクルとなります。

MAGIC1とMAGIC2は互いに干渉しない様にしていますので必ずしもこのサイクルになるとは限りません。これはパラメータ設定によって、ブレークイーブンやトレーリングストップを、はたまた使用するボリンジャーバンドの期間をMAGIC1,MAGIC2のそれぞれで細かく設定できるようにするためです。

 

例)

・MAGIC1はトレーリングストップの幅をATR倍率の0.5に設定しMAGIC2ではATR倍率を2にし幅の違うトレーリングを行うことで勢いのある相場に対応できるMAGIC1と緩やかなトレンド相場で対応するMAGIC2で使用する

・MAGIC1はボリンジャーバンドの期間9のブレイクでエントリー、MAGIC2はボリンジャーバンドの期間

14のブレイクでエントリー

 

というような設定も可能にするためです。

「ボリバンのブレイクアウトでエントリー」という設定は変えられないものの、豊かな決済方法を用意していますので、いろいろバックテストをしてみるのも面白いかと思います。

作者は最適化とかしないタイプなので設定次第では、もっと相性の良い通貨ペアなどがあると思います。二つ同時にポジションを持つ理由としては、決済のタイミングを二つずらした方が収益力自体はあまり変わらないのですが、最大ドローダウンがそちらの方が比較的減る為です。

 

【本EAについて】

勝率55%で損小利大で買ったり負けたりを繰り返しながらも利益を伸ばしていくEAになります。よく販売されている、高勝率型(あるいは勝率100%型)のEAにありがちなコツコツドカンの恐怖に怯えず、精神的にも経済的にも安心できるEAであると思います。また、MT4を使った最適化は一切行っておりません。あくまで基本的な論理に基づくパラメータでのロジックになりますので、バックテストがカーブフィッティングになっている可能性も限りなく低いと考えます。

4児パパ
6人家族、年収500万の家計簿

コメント

タイトルとURLをコピーしました