はじめに
今回のEAで考慮した点の一つが、メモリの使用量の削減です。その為に、バッファを固定し再利用する方法を模索しました。以下が仕様です。ちなみにバッファ固定の取り組み方法は、こちら ですが、記載されているバグは、バージョンアップで改善されたみたい?使用したDATE
指標名 | 値(time,open,hi,low,close) | 平均足 | DeMaker | EMA×4本 | 一定期間の値(高値、中値、安値) |
バッファ数 | 10 | 6 | 50 | 30 | 80 |
ちなみに、EAを稼働した時のメモリ増加量は、1300kBほどです。(タスクマネージャー調べ)多いのか少ないのかは、不明?ホントに削減されているのかな?CopyBuffer()と比べてどうなのか確認していません。。orz
今回、iMA()やiCustom()などの関数を使用せずにEAを作成した結果、前処理(事前計算)が必要となりました。
※前処理とは、初期状態で空のバッファに過去のデータを入れる事。
今回使用した方法は、現在のbarからバッファ分過去の値(time,open,…)を取得するために、バッファ分過去のbarのtimeを取得し、そこから値を取得する方法を取りました。以下がそのtimeの取得コードです。
+---------------------------------------------------------------------------------------------------------+
datetime Cindibox_h::Shiftime(datetime time){ datetime startime; int rates,i=0; startime=time-frametime(timeframes)*60*(range-1); datetime getbars[]; do{ do{ if(i>0)Sleep(500);//一度以上取得に失敗したら一時停止 i++; rates = CopyTime(symbl,timeframes,(datetime)startime,(datetime)time,getbars); if(rates==range)break; }while(i<5); if(rates!=range){startime-=(datetime)frametime(timeframes)*60; i=1;} }while(rates < range); return(startime);+---------------------------------------------------------------------------------------------------------+
この関数で留意した点
1.CopyRates(),CopyTIme()などの関数は、取得に失敗することがあるので対応する。
(特に、異なるペア、異なるタイムフレームを取得する場合、失敗するとこが多かった。)
データを呼び出す前に、関数を抜けている感じがする?ので、sleep(500)を含めて5回試みるようにした。
2.必ず、バッファ数のbarが取得できるtimeを取得する。
barの抜けがある場合の処理を追加してあります。
この関数を元に以下の関数を実行し、バッファに値を取得させています。
ちなみに、Rates以外の値は、各関数内で処理させています。
+---------------------------------------------------------------------------------------------------------+
int Cindibox_h::Run(const datetime nowtime){ MqlRates Sprice[1]; int zero=0,befo=0,hlzero=0; int rates; datetime startime=nowtime; //バッファが空の時 if(bufindex==0)startime=Shiftime(nowtime); do{ rates = CopyRates(symbl,timeframes,(datetime)startime,(int)1,Sprice); if(rates>0){ if(Sprice[0].time != bartimenow){ bartimenow = Sprice[0].time; bufindex++; } zero=ZeroIndex(bufindex,range); hlzero = ZeroIndex(bufindex,HLrange); price[zero] = Sprice[0]; phi[hlzero] = price[zero].high; plw[hlzero] = price[zero].low; if(MLalfa>0 && MSalfa>0 && ON_MA==true)Run_Ma(bufindex); if(ON_Heiken==true) Run_HeikenAshi(bufindex); if(ON_DeMark==true) Run_DeMarker(bufindex); startime=Shiftimeon(startime); befo = ZeroIndex(bufindex+1,range); } } while(price[befo].tick_volume<=0);//バッファが埋まったら脱出 return(bufindex);+---------------------------------------------------------------------------------------------------------+
前回のコメント
前回頂いたコメントを確認していきます。>>datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)にPERIOD_M6とかPERIOD_M20とかPERIOD_M12がないような..。時間の計算が人間業とは思えないトリッキーさでよくわかりませんでした..。なぜSleep()が..。この関数のdatetimeという戻り値の型も変ですよね。
そうなんです。CATCtradeクラスの各インスタンスのCATCtrade::InputdateでPERIOD_M6、PERIOD_M20、PERIOD_M12を使用しているにも関わらず、datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)に対応するコードを記載していませんでした。以下コード
+---------------------------------------------------------------------------------------------------------+
datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef){ switch(timef){ case PERIOD_M1: return(1); case PERIOD_M5: return(5); case PERIOD_M10: return(10); case PERIOD_M15: return(15); case PERIOD_M30: return(30); case PERIOD_H1: return(60); case PERIOD_H4: return(240); default : return(15); } }+---------------------------------------------------------------------------------------------------------+
うん~!初期計画から変更するのを忘れてました。。orz しかし、defaultがなぜ15なの@@?
後でコードを変更しENUM_TIMEFRAMES の値をそのまま使おうと思っていましたが、忘れていました。
以下がENUM_TIMEFRAMESの値 一覧です。なぜ、H1から16385+時間になるんだろう?
PERIOD_M1 | M3 | M5 | M6 | M10 | M30 | H1 | H2 | H3 | H12 | D1 |
1 | 3 | 5 | 6 | 10 | 30 | 16385 | 16386 | 16387 | 16396 | 16408 |
そして、以下のコードが、修正版
+---------------------------------------------------------------------------------------------------------+
int Cindibox_h::frametime(ENUM_TIMEFRAMES timef){ int t; t=timef; if(t>=16385)t=(t-16384)*60; return(t); }+----------------------------------------------------------------------------------------------------------+
トリッキーと評されたコードは、上記に記載しました。やっぱりこんなコードは、スタンダードではないんだろうな(・・?
datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)
の戻り値もおかしいですね。 int型に変更して、datetime Cindibox_h::Shiftime(datetime time)の以下のコードを変更するようにした方が良いのかな?
startime=time - (datetime)frametime(timeframes)*60*(range-1);
>>if(--retry_count!=0) continue;
リトライが動作しない。
partial_closeがfalseだとwhile(partial_close);でループを抜けてしまいます。
指摘されたコードが以下のコードです。
標準ライブラリー(bool CTrade::PositionClose(const string symbol,ulong deviation))より抜粋し、余分?なところを削除したものです。
+----------------------------------------------------------------------------------------------------------+
bool CATCtrade::PositionClose(void){ bool partial_close=false; int retry_count =10; uint retcode =TRADE_RETCODE_REJECT; //--- check stopped if(IsStopped()) return(false); //--- variables string action,result; //--- clean ClearStructures(); do { //--- checking if(PositionSelect(symbl)) { if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { //--- prepare request for close BUY position m_request.type =ORDER_TYPE_SELL; m_request.price=SymbolInfoDouble(symbl,SYMBOL_BID); } else { //--- prepare request for close SELL position m_request.type =ORDER_TYPE_BUY; m_request.price=SymbolInfoDouble(symbl,SYMBOL_ASK); } } else { //--- position not found m_result.retcode=retcode; return(false); } //--- setting request m_request.action =TRADE_ACTION_DEAL; m_request.symbol =symbl; m_request.deviation =deviation; m_request.type_filling=ORDER_FILLING_AON; m_request.volume =PositionGetDouble(POSITION_VOLUME); //--- check volume double max_volume=SymbolInfoDouble(symbl,SYMBOL_VOLUME_MAX); if(m_request.volume>max_volume) { m_request.volume=max_volume; partial_close=true; } else partial_close=false; //--- order check if(!OrderCheck(m_request,m_check_result))return(false); //--- order send if(!OrderSend(m_request,m_result)){ if(--retry_count!=0) continue; return(false); } retcode=TRADE_RETCODE_DONE_PARTIAL; if(partial_close) Sleep(1000); } while(partial_close); return(true); }+----------------------------------------------------------------------------------------------------------+
確認するんだった。。orz デフォルトだとループしないじゃん。勉強になりました。
ループさせる場合は、bool partial_close=true;ですね。。
>>ENUM_ORDER_TYPE CATCtrade::creattype(const int typec)
return(ORDER_TYPE_BUY)とreturn(NULL)を返していますが、どちらも0で同値です。ただ動作には影響ないです。
ENUM_ORDER_TYPEにORDER_TYPE_FLATを作成しなかったMetaQuotes社の仕様決めのいい加減さが原因だと思います。
ポジションの状態を調べるのにPositionSelect()とPositionGetInteger()の2つの関数の組み合わせが必要になりますし。
まず、対象コードの確認
+----------------------------------------------------------------------------------------------------------+
ENUM_ORDER_TYPE CATCtrade::creattype(const int typec){ switch(typec){ case 2: return(ORDER_TYPE_BUY); case -2: return(ORDER_TYPE_SELL); default: return(NULL); } }+----------------------------------------------------------------------------------------------------------+
そして、ENUM_ORDER_TYPEの値の確認
_BUY | _SELL | _BUY_LIMIT | _SELL_LIMIT | _BUY_STOP | _SELL_STOP | _BUY_STOP_LIMIT | _SELL_STOP_LIMIT |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
あらら、指摘の通り_BUYの値が0でした。
さて、どうするか?int型?char型の方が良いかな?にしてdefalt値に-1を入れる手段をとるか?選択に迷います。
それにしても、TYPE_FLATがほしいですね。
>>deviation =10;1pipsは狭すぎではないですか?
とほほです。デフォルトのコードを確認せずに使っちゃダメですね。反省します。
まとめ
情けないほどのバグが発見されました。ご指摘くださった@ahaha_fxtraderさんと匿名さんありがとうございました。
今後に生かしたいと思います。
5 件のコメント :
相変わらずきれいなコードで感服します。
ところでこのブログのアドレスを例のインタビューで曝してもいいですか?
alohafxさんへ
曝しちゃってください。
問題は、このブログがそれだけの価値があるかどうかですが・・・・
インタビュー大変そうですね^^;
頭が下がります。
頑張ってください。
アドレスの件ありがとうございます。
先方でどう編集されるかは分かりませんが。
もう結果出てるんで気楽なもんです。
しかし本名とか顔とかやですよね。しかも勝ってもいないのに。bighopeさんのようにちゃんとインタビューされたかった。
今日例のインタビューが出たのですが。
本名出ちゃってすいません。
ブログのリンクがなくてすいません。
しかし、Mizutoriは、MizuNoriからきていたとは。(?)
alohafxさんへ
記事拝見しました。
日本人初のインタビューご苦労様でした。
カッコイイ~です。
本名が出てしまった件は、(´・∀・`)アラマァ って感じですが、特に問題ない!と言いますか、良い転換点になればと思っています。あまり、お気を使わないようにしてください。インタビューを進めたのは、私ですし・・・・
Mizutori の命名の件は、火の鳥をもじった時の偶然(・・?としておいてください。^^;
では・・
コメントを投稿