//+------------------------------------------------------------------+
//|                                                      canyon2.mq4 |
//|                                                          NKI0122 |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

//マーチン倍率を複利型に変更
//エントリー基準は、全ての値動きから20p動いたら入る。１番目のポジションレートを保存し、そこから20pips逆行しないとエントリーしない。つまり売りと買いのstaticを分ける

#property copyright "NKI0122"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property script_show_inputs
#define OBJ_HEAD (__FILE__+"_")  //オブジェクト接頭名
#define MAGIC 20221001
string butname=OBJ_HEAD+TimeToStr(Time[0]);
enum ENUM_TRADE_TYPE{
   BOTH_SIDE,
   LONG_ONLY,
   SHORT_ONLY
};

#include <stdlib.mqh>
input long key_code = 0;   //PASSWORD
sinput ENUM_TRADE_TYPE trade_type=BOTH_SIDE; //OrderType
input double Lots=0.01;    //ORDER_LOTS
input double Multi_Ratio=1.5; //MultiRatio
//input int Take_Profit   =200; //takeprofit
input int _firstentry_pips=200;  //FirstPosition
input int entry_pips=200;     //NextPosition
input int BUY_Position_MAX=12;   //Nampin Limit Buy Side
input int SELL_Position_MAX=12;  //Nampin Limit Sell Side
input int First_Target_rate= 100;//FirstTarget point
input int Target_rate= 65;  //Target point
input int _nampin_time=0; //Nampin Interval(min)

//input int TOTAL_Position_MAX=30; 
input string Start_TIME="0:00";   //Start time everyday(ServerTime)
input string End_TIME="0:00";     //End time everyday
input string Mon_s_TIME="6:00";  //Monday start time
input string Fri_e_TIME="10:00";  //Friday end time

sinput bool Set_Stop =false;  //set_stop(false:does not set stop)
input int Stop_Offset=200;    //stop_loss point
sinput int slippage=30;    //Slippage


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

//static double init_rate;
int OnInit()
  {
   long pass=(long)AccountNumber()*0+0;
   
   if(key_code!=pass){
      Alert("Auth failed");
      return(INIT_FAILED);
   }
   
   if(BUY_Position_MAX > 20 || SELL_Position_MAX > 20){
      MessageBox("Please check \"Nampin Limit\"!","forbidden number",0);
      return(INIT_FAILED);
   
   }
//---

   Button_Create(butname+"closesell","CLOSE SELL",clrWhite,clrBlue,clrBlack,30,30,10,100,30);
   Button_Create(butname+"closebuy","CLOSE BUY",clrWhite,clrRed,clrBlack,130,30,10,100,30);
   Button_Create(butname+"closeall","CLOSE ALL",clrBlack,clrYellow,clrBlack,230,30,10,100,30);
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,OBJ_HEAD);
  
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool time_allow=false;
   bool week_start=true;
   bool week_end=true;
   week_start=WeekStart_Judge(Mon_s_TIME);
   week_end=WeekEnd_Judge(Fri_e_TIME);
   //Comment(week_end);
   //Comment(week_start,week_end);
   if(week_start==false || week_end==false)return;
   
   time_allow=Trade_time(Start_TIME,End_TIME);
   if(Start_TIME==End_TIME)time_allow=true;
   if(time_allow==true){
      EA_Entry();
      EA_Modify_A();
      EA_Modify_B(OP_SELL);
      EA_Modify_B(OP_BUY);
   }

   
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_OBJECT_CLICK){
      string click_button=sparam;
      if(click_button==butname+"closesell"){
         Comment("closesell");
         EA_Close(OP_SELL);
         
         if(ObjectGetInteger(0,click_button,OBJPROP_STATE)){
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrBlack);
            Sleep(150);
            ObjectSetInteger(0,click_button,OBJPROP_STATE,false);
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrBlue);
         }
      }
      if(click_button==butname+"closebuy"){
         EA_Close(OP_BUY);
         Comment("closebuy");
         if(ObjectGetInteger(0,click_button,OBJPROP_STATE)){
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrBlack);
            Sleep(150);
            ObjectSetInteger(0,click_button,OBJPROP_STATE,false);
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrRed);
         }
      }
      if(click_button==butname+"closeall"){
         Comment("closeall");
         EA_Close(OP_SELL);
         EA_Close(OP_BUY);
         if(ObjectGetInteger(0,click_button,OBJPROP_STATE)){
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrBlack);
            Sleep(150);
            ObjectSetInteger(0,click_button,OBJPROP_STATE,false);
            ObjectSetInteger(0,click_button,OBJPROP_BGCOLOR,clrYellow);
         }
      }
   }
   
   
  }
//+------------------------------------------------------------------+
//ボタンの実装
void Button_Create(string objname,
                     string in_text,
                     color in_color_letter,
                     color in_color_button1,
                     color in_color_button2, //枠の色
                     int x_distance,
                     int y_distance,
                     int font_size,
                     int x_size,
                     int y_size
                     ){
   
   ObjectCreate(0,objname,OBJ_BUTTON,0,0,0);
   ObjectSetInteger(0,objname,OBJPROP_COLOR,in_color_letter);
   ObjectSetInteger(0,objname,OBJPROP_BGCOLOR,in_color_button1);
   ObjectSetInteger(0,objname,OBJPROP_BORDER_COLOR,in_color_button2);
   ObjectSetInteger(0,objname,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,objname,OBJPROP_HIDDEN,true);
   ObjectSetInteger(0,objname,OBJPROP_CORNER,CORNER_LEFT_LOWER);
   
   ObjectSetInteger(0,objname,OBJPROP_XDISTANCE,x_distance);
   ObjectSetInteger(0,objname,OBJPROP_YDISTANCE,y_distance);
   ObjectSetInteger(0,objname,OBJPROP_XSIZE,x_size);
   ObjectSetInteger(0,objname,OBJPROP_YSIZE,y_size);
   ObjectSetInteger(0,objname,OBJPROP_FONTSIZE,font_size);
   ObjectSetString(0,objname,OBJPROP_FONT,"MSゴシック");
   ObjectSetString(0,objname,OBJPROP_TEXT,in_text);

   
}

//月曜日判定
bool WeekStart_Judge(string in_mon_s_time){
   bool ret=true;
   datetime today=TimeCurrent();
   int get_date=TimeDayOfWeek(today);
   if(get_date==1){
      datetime lim_time=StrToTime(in_mon_s_time);
      if(today<lim_time){
         ret=false;
      }
   }
   return ret;
}
//金曜日判定
bool WeekEnd_Judge(string in_fri_e_time){
   bool ret=true;
   datetime today=TimeCurrent();
   int get_date=TimeDayOfWeek(today);
   if(in_fri_e_time=="0:00")return true;
   if(get_date==5){
      datetime lim_time=StrToTime(in_fri_e_time);
      
      if(today>lim_time){
         ret=false;
      }
   }
   
   
   return ret;
}

//設定時間のみエントリーを行う
bool Trade_time(string in_stime,string in_etime){
   bool ret=false;
   
   datetime start_time=0;
   datetime end_time=0;
   start_time=StrToTime(in_stime);
   end_time=StrToTime(in_etime);
   datetime now_time=TimeCurrent();
   //Comment(TimeToStr(start_time),"_",TimeToStr(end_time),"_",TimeToStr(now_time));
   if(now_time>=start_time && now_time<=end_time){
      ret=true;
   }
   return ret;
}
//利食いの設定A初期ロット利食い
void EA_Modify_A(){
   int sell_position=0;
   int buy_position=0;
   int total_position=0;

   CountEAOrder(buy_position,sell_position,total_position);
   if(buy_position==1){
      double first_offset=Point()*First_Target_rate;
      double first_tp_b=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         bool sel=OrderSelect(i,SELECT_BY_POS);
         if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol() || OrderType()!=OP_BUY)continue;
         first_tp_b=OrderOpenPrice()+first_offset;
         bool modi_bool=OrderModify(OrderTicket(),0,0,first_tp_b,0,clrNONE);
      }
   }
   //売りポジションについて
   if(sell_position==1){//現在の売りポジションが１
      double first_tp=0;
      for(int i=OrdersTotal()-1;i>=0;i--){
         bool sel=OrderSelect(i,SELECT_BY_POS);
         //if(sel==false)break;
         if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol())continue;
         if(OrderType()==OP_SELL){
            first_tp=OrderOpenPrice()-Point()*First_Target_rate;                 //エントリーレートからリミット設定
            bool modi_bool=OrderModify(OrderTicket(),0,0,first_tp,0,clrNONE);
            
         }
      }
   }
}
//利食いの設定Bナンピン利食いの設定-目標利益で全部決済
void EA_Modify_B(int in_cmd){
   int sell_position=0;
   int buy_position=0;
   int total_position=0;
   CountEAOrder(buy_position,sell_position,total_position);
   int view_position=0;
   if(in_cmd==OP_SELL){
      view_position=sell_position;
   }else if(in_cmd==OP_BUY){
      view_position=buy_position;
   }
   double tickvalue=MarketInfo(Symbol(),MODE_TICKVALUE); //1.00Lot,Pointの損益
   tickvalue=NormalizeDouble(tickvalue,2);
   double total_lots=0;
   double total_profit=0;
   

   
   //if(view_position==1)target_value=point_value*First_Target_rate;   //ポジションが一つの時
   //Comment(sell_position,tickvalue);
  
   //cmdポジションについて
   if(view_position>1){ //現在のcmdポジションが2以上
      for(int i=OrdersTotal()-1;i>=0;i--){
         bool sel=OrderSelect(i,SELECT_BY_POS);
         if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol())continue;
         if(OrderType()==in_cmd){
            total_lots+=OrderLots();   //現在のcmdロットトータルを返す
            total_profit+=OrderProfit();  //現在のcmdポジションによる総損益を返す
            
         }
      }
      double point_value=total_lots/1*tickvalue;   //トータルロット換算のポイントあたり損益
   //Comment(point_value);
   double target_value=point_value*Target_rate; //この利益があれば利食いたい

      //Comment(total_profit,"_",total_lots,"_",target_value);
      
      if(total_profit>=target_value){                   //含み損益が目標以上になったら
                  
         EA_Close(in_cmd);       //売りポジションが０になるまで決済
         
         
      }           
   }
}
//指定したオーダータイプをクローズ(引数にOrdertype列挙)
void EA_Close(int cmd      //Ordertype
                     ){
 
  
         double close_rate=0;
         if(cmd==OP_BUY){
            close_rate=Bid;
         }else if(cmd==OP_SELL){
            close_rate=Ask;
         }
   //int limit=OrdersTotal();
   for(int i=OrdersTotal()-1;i>=0;i--){
      bool sel=OrderSelect(i,SELECT_BY_POS);
      if(OrderMagicNumber()!= MAGIC || OrderSymbol()!=Symbol() || OrderType()!=cmd)continue;
      bool clo=OrderClose(OrderTicket(),OrderLots(),close_rate,slippage,clrNONE);
   }
   }
   
//同一方向前回ポジションから◯分以上経っているか
bool OrderInterval(int in_minute, int in_cmd){
   bool ret=false;
   int preticket=PrevTicket(in_cmd);
   if(preticket<0)return true;
   int interval=in_minute*60;
   if(OrderSelect(preticket,SELECT_BY_TICKET)){
      if(OrderOpenTime()+interval<TimeCurrent()){
         ret=true;
      }
   }else{
      ret=true;   //前回オーダーが無い時はtrue
   }
   return ret;
}

//前回（最新）同一方向オーダーチケット
int PrevTicket(int in_cmd){
   int ret=-1;
   datetime prev_entry_time=-1;
   
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol() || OrderType()!=in_cmd)continue;
         if(OrderOpenTime()>prev_entry_time){
            prev_entry_time=OrderOpenTime();
            ret=OrderTicket();
         }
      }
   }
   
   return ret;
}


//EAのエントリー判定、エントリー実行
//判定を売り買い分ける。レートの保存も分ける。前回のレートから20p動かないと決済しない。
//ポジションがない時は、全てのレートを動的にベースとする。ポジションがない時は常にstaticに現在値を渡す
//ポジションがある時はOPENpriceをstaticに渡し、次の注文が入るか、決済でゼロになるまで更新しない。売り買いは分けて管理
void EA_Entry(){
   static double init_rate_s; //sellratestatic
   static double init_rate_b;
   if(init_rate_s==0 || init_rate_b==0){  //EA導入時のレートを保存しておく（導入時はエントリーしない）
      init_rate_b=Close[0];
      init_rate_s=Close[0];
   }
   double now_rate=Close[0];
   int buy_posi=0;
   int sell_posi=0;
   int total_posi=0;
   double offset=50;
   CountEAOrder(buy_posi,sell_posi,total_posi);   
   
   if(sell_posi<=0){          //0posiのとき　オーダーが無くなったらここに戻る
      if(now_rate<init_rate_s){  //レートが前回の保存レートより下落したら保存レートを更新
         init_rate_s=now_rate;      
      }
   }
   if(buy_posi<=0){           //買いポジションを持っていない時は、高値を保存、高値から20p下落すると買いポジションを持つように設定
      if(now_rate>init_rate_b){
         init_rate_b=now_rate;
      }
   }

   double move_rate_s=now_rate-init_rate_s;   //現在値と売り保存レートの差
   double move_rate_b=init_rate_b-now_rate;  //買い保存レートから現在値を引く
   double move_pips_b=0;
   double move_pips_s=0;
   double point=Point();
   if(point>0){         //０除算対策
      move_pips_s=move_rate_s/point;    //最小ポイントで割ってpipsを算出（0.1pips）
      move_pips_b=move_rate_b/point;
   }
   int ticket=-1;
   double tp_rate=0;
   bool interval=false;
   
   //Comment(buy_posi,sell_posi,total_posi);
   if(sell_posi<=0 && move_pips_s>=_firstentry_pips){     //前回保存レートから２００ｐ上昇した場合
   //200p以上動いたら保存レートを更新
      //tp_rate=Bid-Point()*Take_Profit;
      
      if(sell_posi<=SELL_Position_MAX && trade_type!=LONG_ONLY){   //売りポジション数がMAX以下（ポジションMAX＋１が実質最大値）かつロングオンリー設定ではない
         double order_lots=Lots;
         
         
            double mul_pow=MathPow(Multi_Ratio,(double)sell_posi);   //既存オーダー数の累乗（0乗は1)
            order_lots=Lots*mul_pow;    //売りポジションが既にある場合はポジション数×マーチン倍率をロットに掛ける
            order_lots=NormalizeDouble(order_lots,2);      //四捨五入
         interval=OrderInterval(_nampin_time,OP_SELL);   
         //Comment(order_lots,"_",sell_posi,"_",mul_pow);
         if(interval)ticket=OrderSend(Symbol(),OP_SELL,order_lots,Bid,slippage,0,0,"",MAGIC,0,clrNONE);     //最初にSLTPの設定はしない
         init_rate_s=Close[0];         //売りオーダーをした時にレートを保存
      }

   }
   
   if(buy_posi<=0 && move_pips_b>=_firstentry_pips){
      //tp_rate=Ask+Point()*Take_Profit;
      
      if(buy_posi<=BUY_Position_MAX && trade_type!=SHORT_ONLY){
         double order_lots=Lots;
         
         
            double mul_pow=MathPow(Multi_Ratio,(double)buy_posi);   //既存オーダー数の累乗（０個なら１）
            order_lots=Lots*mul_pow;
            NormalizeDouble(order_lots,2);            
         interval=OrderInterval(_nampin_time,OP_BUY);
         if(interval)ticket=OrderSend(Symbol(),OP_BUY,order_lots,Ask,slippage,0,0,"",MAGIC,0,clrNONE);
         init_rate_b=Close[0];
      }
   }
 
   if(sell_posi>0 && move_pips_s>=entry_pips){     //前回保存レートから２００ｐ上昇した場合
   //200p以上動いたら保存レートを更新
      //tp_rate=Bid-Point()*Take_Profit;
      
      if(sell_posi<=SELL_Position_MAX && trade_type!=LONG_ONLY){   //売りポジション数がMAX以下（ポジションMAX＋１が実質最大値）かつロングオンリー設定ではない
         double order_lots=Lots;
         
         
            double mul_pow=MathPow(Multi_Ratio,(double)sell_posi);   //既存オーダー数の累乗（0乗は1)
            order_lots=Lots*mul_pow;    //売りポジションが既にある場合はポジション数×マーチン倍率をロットに掛ける
            order_lots=NormalizeDouble(order_lots,2);      //四捨五入
         interval=OrderInterval(_nampin_time,OP_SELL);   
         //Comment(order_lots,"_",sell_posi,"_",mul_pow);
         if(interval)ticket=OrderSend(Symbol(),OP_SELL,order_lots,Bid,slippage,0,0,"",MAGIC,0,clrNONE);     //最初にSLTPの設定はしない
         init_rate_s=Close[0];         //売りオーダーをした時にレートを保存
      }

   }
   
   if(buy_posi>0 && move_pips_b>=entry_pips){
      //tp_rate=Ask+Point()*Take_Profit;
      
      if(buy_posi<=BUY_Position_MAX && trade_type!=SHORT_ONLY){
         double order_lots=Lots;
         
         
            double mul_pow=MathPow(Multi_Ratio,(double)buy_posi);   //既存オーダー数の累乗（０個なら１）
            order_lots=Lots*mul_pow;
            NormalizeDouble(order_lots,2);            
         interval=OrderInterval(_nampin_time,OP_BUY);
         if(interval)ticket=OrderSend(Symbol(),OP_BUY,order_lots,Ask,slippage,0,0,"",MAGIC,0,clrNONE);
         init_rate_b=Close[0];
      }
   }

   //if(ticket>=0){
   //   PrintFormat("[%d]オーダー成功",__LINE__);
   //}
   //損切りの設定
   if(Set_Stop==true && ticket>=0){
      double stoprate=0;
      bool select=false;
      bool modify=false;
      select=OrderSelect(ticket,SELECT_BY_TICKET);
      //if(select==false){
         //printf("[%d]チケットが不正です",__LINE__);                        //デバッグ用コメント
         //return;     //処理終了
      //}
      if(OrderType()==OP_SELL){
         stoprate=OrderOpenPrice()+Point()*Stop_Offset;  //損切り価格を設定
         modify=OrderModify(ticket,0,stoprate,0,0,clrNONE);
      }else if(OrderType()==OP_BUY){
         stoprate=OrderOpenPrice()-Point()*Stop_Offset;
         modify=OrderModify(ticket,0,stoprate,0,0,clrNONE);
      }
      
      //if(modify==true){
        // printf("[%d]オーダー変更チケットNO:%d",__LINE__,ticket);
     // }else{
        // printf("[%d]オーダー変更不可",__LINE__);
     // }
   }
 
}
//現在持っているEAポジションをカウント
void CountEAOrder(int &out_buy,int &out_sell,int &out_total){
   bool select=false;
   int buy_count=0;
   int sell_count=0;
   int total_count=0;
   for(int i=0;i<OrdersTotal();i++){
      select=OrderSelect(i,SELECT_BY_POS);
      
      if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol())continue;
      if(OrderType()==OP_BUY){
         buy_count++;
      }else if(OrderType()==OP_SELL){
         sell_count++;
      }
      total_count=buy_count+sell_count;
      out_buy=buy_count;
      out_sell=sell_count;
      out_total=total_count;
      
   }
   
}
