//+------------------------------------------------------------------+
//|                                            Aki0307_Pivot_001.mq4 |
//|                                        Copyright ｩ 2009, Aki0307 |
//|                                  http://aki0307.blog.shinobi.jp/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ｩ 2009, Aki0307"
#property link      "http://aki0307.blog.shinobi.jp/"

//Pivot値
double dHbop = 0.0;
double dR2 = 0.0;
double dR1 = 0.0;
double dPivot = 0.0;
double dS1 = 0.0;
double dS2 = 0.0;
double dLbop = 0.0;

// NR7
bool bNr7 = true;

//スリップページ
extern int iSlip=3;

//ロット数
extern double dLots=0.1;

// マジックNo
extern int iMagicNo = 20090407;

//注文リトライ用
extern int iRetry_Cnt = 1;
extern int iWait_Time = 10;

//マネーマネージメント用
extern bool bMM = false;
extern double dRisk = 1.0;
extern double dVs_Usd = 0.01;
extern double dMax_Lots = 50.0;
extern double dMin_Lots = 0.1;

// 時間足用
datetime dtTimeFrame = 0;
datetime dtNowTimeFrame = 0;

// ログファイル名
string sLogFileName = "";

//ロット数(実態)
double dEntry_Lots=0.1;

////////////////////////////////////////////////////////////////////
// expert initialization function
////////////////////////////////////////////////////////////////////
int init(){

    // ファイル名を生成する（EA名+YYYYMMDD)
    sLogFileName = "Aki0307_Pivot_001_"+TimeYear(TimeLocal())+TimeMonth(TimeLocal())+TimeDay(TimeLocal())+".csv";

    return(0);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start(){

    // 日足に変化があると中に入る
    if(dtTimeFrame<iTime(NULL,PERIOD_D1,0)) {
        dtTimeFrame=iTime(NULL,PERIOD_D1,0);
        Aki0307_Pivot();
        Aki0307_Nr7();
        // すでに出している注文と建て玉をクローズする
        Ordclose();
        call_MM();
        call_Trade();

    }

    // 今の時間足に変化があると中に入る
    if(dtNowTimeFrame<iTime(NULL,0,0)) {
        dtNowTimeFrame=iTime(NULL,0,0);
        Aki0307_PrintDetails();
    }


    return(0);
}


/////
// Pivotの計算
////
int Aki0307_Pivot(){

    // 日足の終値、高値、安値を算出
    double dClose = iClose(NULL,PERIOD_D1,1);
    double dHigh = iHigh(NULL,PERIOD_D1,1);
    double dLow = iLow(NULL,PERIOD_D1,1);

    // Pivot算出
    dPivot = NormalizeDouble((dClose + dHigh + dLow)/3,Digits);

    // レジスタンス算出
    dR1 = NormalizeDouble(dPivot * 2 - dHigh,Digits);
    dR2 = NormalizeDouble(dPivot - dHigh + dLow,Digits);

    // サポート算出
    dS1 = NormalizeDouble(dPivot * 2 - dLow,Digits);
    dS2 = NormalizeDouble(dPivot + dHigh - dLow,Digits);

    // ブレイクアウト算出
    dHbop = NormalizeDouble(dPivot * 2 - dLow * 2 + dHigh,Digits);
    dLbop = NormalizeDouble(dPivot * 2 - dHigh * 2 + dLow,Digits);

    return (0);
}

/////
// Nr7の計算
////
int Aki0307_Nr7(){
    bNr7 = true;
    for(int iCnt = 7; iCnt>1;iCnt--){
        if(iHigh(NULL,PERIOD_D1,1) - iLow(NULL,PERIOD_D1,1) > iHigh(NULL,PERIOD_D1,iCnt) - iLow(NULL,PERIOD_D1,iCnt)){
            bNr7 = false;
            iCnt = 0;
        }
    }
    return (0);
}

////////////////////////////////////////////////////////////////////
// トレード判定
////////////////////////////////////////////////////////////////////
int call_Trade(){

    if(bNr7 == false && TimeDayOfWeek(TimeCurrent()) != 1){
        // 買い注文
        Aki0307_OrderSend(Symbol(), OP_BUYLIMIT, dEntry_Lots, dR1, iSlip, dLbop, dPivot, "R1買い注文", iMagicNo, 0, Blue);

       // 買い注文
        Aki0307_OrderSend(Symbol(), OP_BUYLIMIT, dEntry_Lots, dR2, iSlip, dLbop, dR1, "R2買い注文", iMagicNo, 0, Blue);


        // 売り注文
        Aki0307_OrderSend(Symbol(), OP_SELLLIMIT, dEntry_Lots, dS1, iSlip, dHbop, dPivot, "S1売り注文", iMagicNo, 0, Red);

        // 売り注文
        Aki0307_OrderSend(Symbol(), OP_SELLLIMIT, dEntry_Lots, dS2, iSlip, dHbop, dS1, "S2売り注文", iMagicNo, 0, Red);
    }
    return(0);
}

////////////////////////////////////////////////////////////////////
// EA状態表示
////////////////////////////////////////////////////////////////////
void  Aki0307_PrintDetails()
{
   string sComment   = "";
   string sp         = "----------------------------------------\n";
   string NL         = "\n";
	string sDirection = "";
   sComment = "Aki0307_Window_Open_001" + NL;
   sComment = sComment + sp;   
   sComment = sComment + "Open[0]=" + DoubleToStr(iOpen(NULL,PERIOD_D1,0),Digits) + " | "; 
   sComment = sComment + "Close[0]=" + DoubleToStr(iClose(NULL,PERIOD_D1,0),Digits) + " | "; 
   sComment = sComment + "High[0]=" + DoubleToStr(iHigh(NULL,PERIOD_D1,0),Digits) + " | "; 
   sComment = sComment + "Low[0]=" + DoubleToStr(iLow(NULL,PERIOD_D1,0),Digits) + NL; 
   sComment = sComment + sp;   
   sComment = sComment + "Open[1]=" + DoubleToStr(iOpen(NULL,PERIOD_D1,1),Digits) + " | "; 
   sComment = sComment + "Close[1]=" + DoubleToStr(iClose(NULL,PERIOD_D1,1),Digits) + " | "; 
   sComment = sComment + "High[1]=" + DoubleToStr(iHigh(NULL,PERIOD_D1,1),Digits) + " | "; 
   sComment = sComment + "Low[1]=" + DoubleToStr(iLow(NULL,PERIOD_D1,1),Digits) + NL; 
   sComment = sComment + sp;   
   sComment = sComment + "dPivot=" + DoubleToStr(dPivot,Digits) + " | "; 
   sComment = sComment + "dR1=" + DoubleToStr(dR1,Digits) + " | "; 
   sComment = sComment + "dR2=" + DoubleToStr(dR2,Digits) + " | "; 
   sComment = sComment + "dS1=" + DoubleToStr(dS1,Digits) + " | "; 
   sComment = sComment + "dS2=" + DoubleToStr(dS2,Digits) + " | "; 
   sComment = sComment + "dHbop=" + DoubleToStr(dHbop,Digits) + " | "; 
   sComment = sComment + "dLbop=" + DoubleToStr(dLbop,Digits) + NL; 
   sComment = sComment + sp;   
   Comment(sComment);
}

////////////////////////////////////////////////////////////////////
// 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);
}
////////////////////////////////////////////////////////////////////
// 注文とポジションのクローズ
////////////////////////////////////////////////////////////////////
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;
                }
            }
        }
    }
}
////////////////////////////////////////////////////////////////////
// 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);
}

////////////////////////////////////////////////////////////////////
// マネーマネージメント
////////////////////////////////////////////////////////////////////
double call_MM(){
    if(bMM == true){
        dEntry_Lots = AccountEquity()*dVs_Usd/100000*dRisk;
        dEntry_Lots = MathMin(dMax_Lots,MathMax(dMin_Lots,dEntry_Lots));
        dEntry_Lots = NormalizeDouble(dEntry_Lots,1);
    }else{
        dEntry_Lots = dLots;
    }

    return(dEntry_Lots);
}

