//+------------------------------------------------------------------+
//|                                         Aki0307_GBPJPY14_007.mq4 |
//|                                        Copyright ｩ 2009, Aki0307 |
//|                                  http://aki0307.blog.shinobi.jp/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ｩ 2009, Aki0307"
#property link      "http://aki0307.blog.shinobi.jp/"

//エントリーする時分
extern int iEntryHH=14;
extern int iEntryMM=0;

//クローズする時分
extern int iCloseHH=4;
extern int iCloseMM=0;

//エントリーするPip
extern int iEntryPip=20;

//リミットとストップ値
extern int iLimit=20;
extern int iStop=20;

//スリップページ
extern int iSlip=3;

//ロット数
extern double dLots=0.1;

// トレーリングストップ用フラグ
extern bool bTrailingStop = false;

// マジックNo
extern int iMagicNo = 307004;

//マネーマネージメント用
extern bool bMM = false;
extern int iRisk = 1;
extern double dVs_Usd = 0.01;
extern double dMax_Lots = 50.0;
extern double dMin_Lots = 0.1;

//注文リトライ用
extern int iRetry_Cnt = 1;
extern int iWait_Time = 10;

// 時間足用
datetime dtTimeFrame = 0;

//エントリーするPip(実態)
double dEntryPip=0.0;

//リミットとストップ値(実態)
double dLimit=0.0;
double dStop=0.0;

//ロット数(実態)
double dEntry_Lots=0.1;

// ログファイル名
string sLogFileName = "";

// 買い注文用変数
int iBuyTicket = 0;
double dBuyEntry = 0.0;
double dBuyLimit = 0.0;
double dBuyStop = 0.0;

// 売り注文用変数
int iSellTicket = 0;
double dSellEntry = 0.0;
double dSellLimit = 0.0;
double dSellStop = 0.0;

////////////////////////////////////////////////////////////////////
// expert initialization function
////////////////////////////////////////////////////////////////////
int init(){
    dEntryPip = iEntryPip * Point;
    dLimit = iLimit * Point;
    dStop = iStop * Point;

    // ファイル名を生成する（EA名+YYYYMMDD)
    sLogFileName = "Aki0307_GBPJPY14_007_"+TimeYear(TimeLocal())+TimeMonth(TimeLocal())+TimeDay(TimeLocal())+".csv";

    return(0);
}

////////////////////////////////////////////////////////////////////
// expert deinitialization function
////////////////////////////////////////////////////////////////////
int deinit(){
   return(0);
}

////////////////////////////////////////////////////////////////////
// expert start function
////////////////////////////////////////////////////////////////////
int start(){

    double dLimitOrder = 0;
    double dStopOrder = 0;

    // トレーリングストップ機能呼び出し
    TralStop();

    // 売買注文実行
    EntryTry();

    // 売買注文実行
    EntryClose();

    // 今の時間を取得時間足に変化があると中に入る
    if(dtTimeFrame<iTime(NULL,0,0)) {
        dtTimeFrame=iTime(NULL,0,0);

        //現在の時間を取得
        int iNowHH=TimeHour(TimeCurrent());
        int iNowMM=TimeMinute(TimeCurrent());

        // 時間がクローズと等しい場合は、手仕舞いを行う
        if((iCloseHH == iNowHH) && (iCloseMM == iNowMM)){
            Ordclose();

            // 設定値の初期化
            iBuyTicket = 0;
            dBuyEntry = 0.0;
            dBuyLimit = 0.0;
            dBuyStop = 0.0;

            iSellTicket = 0;
            dSellEntry = 0.0;
            dSellLimit = 0.0;
            dSellStop = 0.0;

        }

        // 時間がエントリーと等しい場合は、発注処理をする
        if((iEntryHH == iNowHH) && (iEntryMM == iNowMM)){
            //ロット数の計算
            MM();

            // 買い注文エントリー値の計算
            dBuyEntry = Ask + dEntryPip;

            //売り注文エントリー値の計算
            dSellEntry = Bid - dEntryPip;
        }
    }

    return(0);
}


////////////////////////////////////////////////////////////////////
// 注文の実行
////////////////////////////////////////////////////////////////////
int EntryTry(){

    // 買い注文のチケットNoが0でエントリー値が設定されていたら注文を判定
    if(iBuyTicket == 0 && dBuyEntry != 0.0){
        if(Ask >= dBuyEntry){
            iBuyTicket = Aki0307_OrderSend(Symbol(), OP_BUY, dEntry_Lots, Ask, iSlip, 0.0, 0.0, "買い注文", iMagicNo, 0, Red);
            if(iBuyTicket == -1){
                iBuyTicket = 0;
            } else {
                OrderSelect(iBuyTicket, SELECT_BY_TICKET, MODE_TRADES);
                dBuyEntry = OrderOpenPrice();
                // 買い注文のリミットの計算
                if(dLimit != 0.0){
                    dBuyLimit = dBuyEntry + dLimit;
                }else{
                    dBuyLimit = 0;
                }
                // 買い注文ストップの計算
                if(dStop != 0.0){
                    dBuyStop = dBuyEntry - dStop;
                }else{
                    dBuyStop = 0;
                }
            }
        }
    }

    // 売り注文のチケットNoが0でエントリー値が設定されていたら注文を判定
    if(iSellTicket == 0 && dSellEntry != 0.0){
        if(Bid <= dSellEntry){
            iSellTicket = Aki0307_OrderSend(Symbol(), OP_SELL, dEntry_Lots, Bid, iSlip, 0.0, 0.0, "売り注文", iMagicNo, 0, Blue);
            if(iSellTicket == -1){
                iSellTicket = 0;
            } else {
                OrderSelect(iSellTicket, SELECT_BY_TICKET, MODE_TRADES);
                dSellEntry = OrderOpenPrice();
                // 売り注文のリミットの計算
                if(dLimit != 0){
                    dSellLimit = dSellEntry - dLimit;
                }else{
                    dSellLimit = 0;
                }
                // 売り注文ストップの計算
                if(dStop != 0){
                    dSellStop = dSellEntry + dStop;
                }else{
                    dSellStop = 0;
                }
            }
        }
    }
    return (0);
}

////////////////////////////////////////////////////////////////////
// ポジションを閉じる
////////////////////////////////////////////////////////////////////
int EntryClose(){

    bool bRet = false;


    // 買い注文のチケットNoが指定されていれば、ポジションを閉じるか判定する
    if(iBuyTicket != 0 && OrderSelect(iBuyTicket, SELECT_BY_TICKET, MODE_TRADES) == true){
        // リミットよりも上か、ストップより下の場合ポジションを閉じる
        if(dBuyLimit <= Bid && dBuyLimit != 0.0){
            bRet = Aki0307_OrderClose(iBuyTicket, dEntry_Lots, Bid, iSlip, Yellow);
            if(bRet == true){
                iBuyTicket = 0;
                dBuyEntry = 0.0;
                dBuyLimit = 0.0;
                dBuyStop = 0.0;
            }
        }
        if(dBuyStop != 0.0 && dBuyStop >= Bid){
            bRet = Aki0307_OrderClose(iBuyTicket, dEntry_Lots, Bid, iSlip, Yellow);
            if(bRet == true){
                iBuyTicket = 0;
                dBuyEntry = 0.0;
                dBuyLimit = 0.0;
                dBuyStop = 0.0;
            }
        }
    }

    // 売り注文のチケットNoが指定されていれば、ポジションを閉じるか判定する
    if(iSellTicket != 0 && OrderSelect(iSellTicket, SELECT_BY_TICKET, MODE_TRADES) == true){
        // リミットよりも上か、ストップより下の場合ポジションを閉じる
        if(dSellLimit >= Ask && dSellLimit != 0.0){
            bRet = Aki0307_OrderClose(iSellTicket, dEntry_Lots, Ask, iSlip, Yellow);
            if(bRet == true){
                iSellTicket = 0;
                dSellEntry = 0.0;
                dSellLimit = 0.0;
                dSellStop = 0.0;
            }
        }
        if(dSellStop != 0 && dSellStop <= Ask){
            bRet = Aki0307_OrderClose(iSellTicket, dEntry_Lots, Ask, iSlip, Yellow);
            if(bRet == true){
                iSellTicket = 0;
                dSellEntry = 0.0;
                dSellLimit = 0.0;
                dSellStop = 0.0;
            }
        }
    }

    return (0);
}

////////////////////////////////////////////////////////////////////
// 注文とポジションのクローズ
////////////////////////////////////////////////////////////////////
int Ordclose(){
    // 持っている注文数を取得
    int iTotal = OrdersTotal();

    // 注文があればポジションクローズと注文のキャンセルを実施
    if(iTotal > 0){
        for(int i = iTotal -1; i >= 0; i-- ){
            // オーダー特定
            bool bSelected = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
            // マジックNoを判定して、自分が出したオーダーかチェック
            if(bSelected == true && OrderMagicNumber() == iMagicNo){
                // オーダーの種類を特定
                int iType = OrderType();
                switch(iType){
                    // Longポジション
                    case OP_BUY:
                        Aki0307_OrderClose(OrderTicket(), OrderLots(), Bid, iSlip, LawnGreen);
                        break;
                    // Shortポジション
                    case OP_SELL:
                        Aki0307_OrderClose(OrderTicket(), OrderLots(), Ask, iSlip, LawnGreen);
                        break;
                    // 注文中（指値買、指値売、逆指値買、逆指値売）
                    case OP_BUYLIMIT:
                    case OP_BUYSTOP:
                    case OP_SELLLIMIT:
                    case OP_SELLSTOP:
                        Aki0307_OrderDelete(OrderTicket());
                        break;
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////////////
// トレーリングストップ機能
////////////////////////////////////////////////////////////////////
int TralStop(){

    double dOpenPrice = 0;
    double dStopPrice = 0;

    if(bTrailingStop == false){
        return(0);
    }

    // 持っている注文数を取得
    int iTotal = OrdersTotal();

    // 注文があればトレーリングストップ実施
    if(iTotal > 0){
        for(int i = iTotal -1; i >= 0; i-- ){

            // オーダー特定
            bool bSelected = OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
            // マジックNoを判定して、自分が出したオーダーかチェック
            if(bSelected == true && OrderMagicNumber() == iMagicNo){

                // オーダーの種類を特定
               int iType = OrderType();
               switch(iType){

                   // Longポジション
                   case OP_BUY:
                       // ポジションを持ったときの価格
                       dOpenPrice = dBuyEntry;
                       // 現在のストップ価格
                       dStopPrice = dBuyStop;

                       // 利益が出ているか判定
                       if(Bid > dOpenPrice){
                           // 利益が出ていればトレール値より上か判定
                           if(Bid-dStopPrice > dStop){
                               // 利益が出ていて、トレール値より上の場合はストップ価格を変更
                               dBuyStop = Bid-dStop;
                           }
                       }
                       break;

                   // Shortポジション
                   case OP_SELL:
                       // ポジションを持ったときの価格
                       dOpenPrice = dSellEntry;
                       // 現在のストップ価格
                       dStopPrice = dSellStop;
                       // 利益が出ているか判定
                       if(Ask < dOpenPrice){
                           // 利益が出ていればトレール値より上か判定
                           if(dStopPrice-Ask > dStop){
                               // 利益が出ていて、トレール値より上の場合はストップ価格を変更
                               dSellStop = Ask + dStop;
                           }
                       }
                       break;
                }
            }
        }
    }
    return (0);
}


////////////////////////////////////////////////////////////////////
// マネーマネージメント（MM）機能
////////////////////////////////////////////////////////////////////
double MM(){
    // MMが有効化判定
    if(bMM == true){
        // 現在の口座金額をドル建てに返還して、1万ドルで0.1になるように計算する。
        // iRiskはレバッジを意味させている
        dEntry_Lots = AccountEquity()*dVs_Usd/100000*iRisk;
        // 計算で出したロット数を最大ロット数/最小ロット数と比較して最終的なロット数を決定
        dEntry_Lots = MathMin(dMax_Lots,MathMax(dMin_Lots,dEntry_Lots));
        // 計算で出したロット数を小数点1位までに四捨五入する
        dEntry_Lots = NormalizeDouble(dEntry_Lots,1);
    }else{
        // 有効じゃない場合は、外部パラメータで指定されたロット数を設定
        dEntry_Lots = dLots;
    }

    return(dEntry_Lots);
}

////////////////////////////////////////////////////////////////////
// OrderSend機能（リトライ機能つき）
////////////////////////////////////////////////////////////////////
int Aki0307_OrderSend(string sSymbol, int iCmd, double dVolume, double dPrice, int iSlippage, double dStoploss, double dTakeprofit, string sComment="", int iMagic=0, datetime dExpiration=0, color cColor=CLR_NONE){
    // 復帰値
    int iRet = 0;
    // 現在の価格
    int iBid = Bid;

    //ファイルハンドル
    int iHandle=0; 

    int iErrorCode = 0;

    // リトライ回数に関係なく、指定されたパラメータでOrderSendを呼び出す
    iRet = OrderSend(sSymbol, iCmd, dVolume, dPrice, iSlippage, dStoploss, dTakeprofit, sComment, iMagic, dExpiration, cColor);
    if(iRet == -1){
        iErrorCode = GetLastError();
        Print("Aki0307_OrderSend Error:",iErrorCode);
        iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
        FileSeek(iHandle, 0, SEEK_END);
        FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderSend", sSymbol, iCmd, dVolume, dPrice, iSlippage, dStoploss, dTakeprofit, sComment, iMagic, dExpiration, cColor, iErrorCode);
        FileClose(iHandle);

        // 1回目のOrderSendがエラーになったら、通るまでリトライ回数分OrderSendを呼び出す
        for(int iCnt = 0; iCnt < iRetry_Cnt; iCnt++){
            //まずは間隔をあける
            Sleep(iWait_Time);

            // OrderSend呼び出し。注文価格は、現在の価格と現在の最新価格との差を反映させる
            iRet = OrderSend(sSymbol, iCmd, dVolume, dPrice + iBid - MarketInfo(sSymbol, MODE_BID), iSlippage, dStoploss, dTakeprofit, sComment, iMagic, dExpiration, cColor);
            if(iRet == -1){
                iErrorCode = GetLastError();
                Print("Aki0307_OrderSend Error:",iErrorCode," iCnt:", iCnt);
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderSendRetry", iCnt, sSymbol, iCmd, dVolume, dPrice + iBid - MarketInfo(sSymbol, MODE_BID), iSlippage, dStoploss, dTakeprofit, sComment, iMagic, dExpiration, cColor, iErrorCode);
                FileClose(iHandle);
            } else {
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderSendRetryOK", iCnt, sSymbol, iCmd, dVolume, dPrice + iBid - MarketInfo(sSymbol, MODE_BID), iSlippage, dStoploss, dTakeprofit, sComment, iMagic, dExpiration, cColor);
                FileClose(iHandle);
                iCnt = iRetry_Cnt;
            }
            // 現在の価格を置き換え
            iBid = MarketInfo(sSymbol, MODE_BID);
        }
    }

    return(iRet);
}

////////////////////////////////////////////////////////////////////
// OrderClose機能（リトライ機能つき）
////////////////////////////////////////////////////////////////////
bool Aki0307_OrderClose(int iTicket, double dLots, double dPrice, int iSlippage, color cColor=CLR_NONE){
    // 復帰値
    bool bRet = false;
    // 現在の価格
    int iBid = Bid;

    //ファイルハンドル
    int iHandle=0; 

    int iErrorCode = 0;

    // リトライ回数に関係なく、指定されたパラメータでOrderCloseを呼び出す
    bRet = OrderClose(iTicket, dLots, dPrice, iSlippage, cColor);
    if(bRet == false){
        iErrorCode = GetLastError();
        Print("Aki0307_OrderClose Error:",iErrorCode);
        iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
        FileSeek(iHandle, 0, SEEK_END);
        FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderClose", iTicket, dLots, dPrice, iSlippage, cColor, iErrorCode);
        FileClose(iHandle);

        // 1回目のOrderCloseがエラーになったら、通るまでリトライ回数分OrderCloseを呼び出す
        for(int iCnt = 0; iCnt < iRetry_Cnt; iCnt++){
            //まずは間隔をあける
            Sleep(iWait_Time);

            // OrderClose呼び出し。注文価格は、現在の価格と現在の最新価格との差を反映させる
            bRet = OrderClose(iTicket, dLots, dPrice + iBid - MarketInfo(Symbol(), MODE_BID), iSlippage, cColor);
            if(bRet == false){
                iErrorCode = GetLastError();
                Print("Aki0307_OrderClose Error:",iErrorCode," iCnt:", iCnt);
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderCloseRetry", iCnt, iTicket, dLots, dPrice + iBid - MarketInfo(Symbol(), MODE_BID), iSlippage, cColor, iErrorCode);
                FileClose(iHandle);
            } else {
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderCloseRetryOK", iCnt, iTicket, dLots, dPrice + iBid - MarketInfo(Symbol(), MODE_BID), iSlippage, cColor);
                FileClose(iHandle);
                iCnt = iRetry_Cnt;
            }
            // 現在の価格を置き換え
            iBid = MarketInfo(Symbol(), MODE_BID);
        }
    }

    return(bRet);
}

////////////////////////////////////////////////////////////////////
// OrderDelete機能（リトライ機能つき）
////////////////////////////////////////////////////////////////////
bool Aki0307_OrderDelete(int iTicket, color cColor=CLR_NONE){
    // 復帰値
    bool bRet = false;

    //ファイルハンドル
    int iHandle=0; 

    int iErrorCode = 0;

    // リトライ回数に関係なく、指定されたパラメータでOrderDeleteを呼び出す
    bRet = OrderDelete(iTicket, cColor);
    if(bRet == false){
        iErrorCode = GetLastError();
        Print("Aki0307_OrderDelete Error:",iErrorCode);
        iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
        FileSeek(iHandle, 0, SEEK_END);
        FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderDelete", iTicket, cColor, iErrorCode);
        FileClose(iHandle);

        // 1回目のOrderDeleteがエラーになったら、通るまでリトライ回数分OrderDeleteを呼び出す
        for(int iCnt = 0; iCnt < iRetry_Cnt; iCnt++){
            //まずは間隔をあける
            Sleep(iWait_Time);

            // OrderDelete呼び出し。
            bRet = OrderDelete(iTicket, cColor);
            if(bRet == false){
                iErrorCode = GetLastError();
                Print("Aki0307_OrderDelete Error:",iErrorCode," iCnt:", iCnt);
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderDeleteRetry", iCnt, iTicket, cColor, iErrorCode);
                FileClose(iHandle);
            } else {
                iHandle = FileOpen(sLogFileName,FILE_READ|FILE_WRITE|FILE_CSV,'\t');
                FileSeek(iHandle, 0, SEEK_END);
                FileWrite(iHandle,TimeToStr(TimeCurrent(), TIME_DATE),TimeToStr(TimeCurrent(), TIME_SECONDS), "Aki0307_OrderDeleteRetryOK", iCnt, iTicket, cColor);
                FileClose(iHandle);
                iCnt = iRetry_Cnt;
            }
        }
    }

    return(bRet);
}


