"Магик" или что-нибудь еще (?)

 
По ходу жизни возникают уровни на пробой, где можно поставить BuyStop или SellStop и мимоходом снять скальп в несколько пипсов (почему не подобрать, если лежит?).

Поскольку эти уровни возникают достаточно редко, можно как-то автоматизировать:

1. Пишем советник, который закрывает прибыльные позы (кстати - рефреш куда-нибудь вставлять надо?):

extern double DesirePips = 5;
extern int    Slippage   = 5;
//----
void start()
{
bool   Result;
int    i,Pos,Error,Total;
int    Dgts=MarketInfo(Symbol(),MODE_DIGITS);
  Total=OrdersTotal();
  if(Total>0)
  {
     for(i=Total-1; i>=0; i--) 
     {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==true) 
        {
           Pos=OrderType();
           if((Pos==OP_BUY || Pos==OP_SELL) && 
              OrderProfit()>=DesirePips*Point
             )
           {
              if(Pos==OP_BUY)
              Result=OrderClose(OrderTicket(),
                                OrderLots(),
                                NormalizeDouble(MarketInfo(Symbol(),
                                                           MODE_BID),
                                                Dgts),
                                Slippage,
                                CLR_NONE);
              if(Pos==OP_SELL)
              Result=OrderClose(OrderTicket(),
                                OrderLots(),
                                NormalizeDouble(MarketInfo(Symbol(),
                                                           MODE_ASK),
                                                Dgts),
                                Slippage,
                                CLR_NONE);
              if(Result!=true) 
              { 
                 Error=GetLastError(); 
                 Alert("Closer LastError = ",Error); 
              }
              else Error=0;
           }
        }
     }
  }
  return;

2. Первый вариант (не очень интересный): пишем скрипт на открытие позы:

#property copyright ""
#property link      ""
#property show_inputs // Если есть желание менять экстерны в процессе
//+------------------------------------------------------------------+
extern int  Interest   = 10;   // Выделить процент FreeMargin на позу
extern int  DistSL     = 85;   // StopLoss в пунктах
extern int  DistTP     = 100;  // TakeProfit в пунктах
extern int  Slippage   = 7;    // Проскальзывание в пунктах
extern bool StopLoss   = true; // Ставить или нет StopLoss
extern bool TakeProfit = true; // Ставить или нет TakeProfit
extern bool CreateGif  = true; // Создать или нет рисунок
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
double MarginCalculate(string symbol,double volume)
//+------------------------------------------------------------------+
//|                                     Взято из MarginCalculate.mq4 |
//|                                  'MarginCalculate' |
//|                      Copyright © 2006, MetaQuotes Software Corp. |
//+------------------------------------------------------------------+
{
   string first    = StringSubstr(symbol,0,3);
   string second   = StringSubstr(symbol,3,3);
   string currency = AccountCurrency();
   double leverage = AccountLeverage();
   double contract = MarketInfo(symbol,MODE_LOTSIZE);
   double bid      = MarketInfo(symbol,MODE_BID);
//---- допускаем только стандартные форексные символы XXXYYY
   if(StringLen(symbol)!=6)
   {
      Print("MarginCalculate: '",symbol,
            "' must be standard forex symbol XXXYYY");
      return(0.0);
   }
//---- проверка наличия данных
   if(bid<=0 || contract<=0) 
   {
      Print("MarginCalculate: no market information for '",
             symbol,"'");
      return(0.0);
   }
//---- проверяем самые простые варианты - без кроссов
   if(first==currency)   return(contract*volume/leverage);
   if(second==currency)  
      return(contract*MarketInfo(symbol,MODE_BID)*volume/leverage);
//---- проверяем обычные кроссы, ищем прямое преобразование
//---- через валюту депозита
   string base=currency+first;
   if(MarketInfo(base,MODE_BID)>0) 
      return(contract/MarketInfo(base,MODE_BID)*volume/leverage);
//---- попробуем наоборот
   base=first+currency; 
   if(MarketInfo(base,MODE_BID)>0) 
      return(contract*MarketInfo(base,MODE_BID)*volume/leverage);
//---- нет возможности прямого перерасчета
   Print("MarginCalculate: can not convert '",symbol,"'");
   return(0.0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void start() 
{
double SL=0, TP=0, Stake, Share, MarginLots;
int    ticket=0, MinLotDgts, i;
double MinLot=MarketInfo(Symbol(),MODE_MINLOT);   
double MaxLot=MarketInfo(Symbol(),MODE_MAXLOT);   
double LotStep=MarketInfo(Symbol(),MODE_LOTSTEP);   
int    Dgts=MarketInfo(Symbol(),MODE_DIGITS);
string FileName, str;     
//----
   Share=0.01*Interest;
   if(Share>1.0) Share=1.0; // Часть не бывает больше целого
   if(Share<0) Share=0;    // (???)
   // Чему равен MinLot? 0.01, 0.1 или ...
   if(MinLot<0.1) MinLotDgts=2;
   else
   {
      if(MinLot<1.0) MinLotDgts=1;
      else MinLotDgts=0;
   }
   // Залог на 1 MinLot
   MarginLots=MarginCalculate(Symbol(),MinLot);
   if(MarginLots<0.01) return;
   if(AccountFreeMargin()<MarginLots)
   {
      Alert("Open_BUY: No maney...");
      return;
   }
   // Сколько MinLot'ов разрешили себе позволить на позу?
   Stake=NormalizeDouble(AccountFreeMargin()*Share/MarginLots,0);
   // Если выделенная часть депо будет меньше минимально допустимого
   // лота, поза будет открыта на минимальный лот
   if(Stake<1) Stake=MinLot;
   else 
   {
      Stake=NormalizeDouble(Stake*MinLot,MinLotDgts);
      // Если выделенная часть депо будет больше максимально
      // допустимого лота, поза будет открыта на максимальный лот
      if(Stake>MaxLot) Stake=MaxLot;
      else while(AccountFreeMargin()<MarginCalculate(Symbol(),Stake))
                 Stake=Stake-LotStep;
   }
   RefreshRates();
   if(StopLoss==true) SL=Bid-DistSL*Point;
   if(TakeProfit==true) TP=Ask+DistTP*Point;
   ticket=OrderSend(Symbol(),OP_BUY,Stake,
                    // Не смотря на рефреш вместо Ask ставим:
                    NormalizeDouble(MarketInfo(Symbol(),MODE_ASK),Dgts), 
                    Slippage,
                    NormalizeDouble(SL,Dgts),
                    NormalizeDouble(TP,Dgts),
                    "",0,0,CLR_NONE);
   if(ticket<=0) Alert("Open_BUY LastError: ",GetLastError()); 
   else
   { 
      if(CreateGif==true)
      {
         //    рисуем, если заказано
         datetime curdate=TimeCurrent();
         FileName=Symbol()+"_BUY_"+TimeYear(curdate);
         i=TimeMonth(curdate);
         if(i<10)
         {
            str="0"+i;
            FileName=FileName+str;
         }
         else FileName=FileName+i;
         i=TimeHour(curdate);
         if(i<10)
         {
            str="0"+i;
            FileName=FileName+str;
         }
         else FileName=FileName+i;
         i=TimeMinute(curdate);
         if(i<10)
         {
            str="0"+i;
            FileName=FileName+str;
         }
         else FileName=FileName+i;
         i=TimeSeconds(curdate);
         if(i<10)
         {
            str="0"+i;
            FileName=FileName+str;
         }
         else FileName=FileName+i;
         FileName=FileName+".gif";
         WindowScreenShot(FileName,800,600); 
      }
   }
   return;
}

И первый вопрос: можно ли что-то добавить в скрипт и в советник, чтоб советник закрывал только позы, открытые этим скриптом? и проходил мимо остальных.

И второй вопрос (вариант более интересный): можно ли написать скрипт на открытие Stop-ордера так, чтоб советник закрывал только позы, открытые после пробоя именно этих ордеров? и проходил мимо остальных.


Звиняйте за обилие кода - я не программист и мне надо, чтоб если чего не знаю, первый раз показали пальцем конкретно: это впиши сюда, а это туда. А не объясняли на словах :).



 

Вот такую штуку увидел - OrderProfit()>=DesirePips*Point

Это неправильно OrderProfit() в деньгах исчисляется.

Все остальное решаеются при помощи магика. В советнике делаешь три переменных Magic_1...2...3 Советник открывает свои ордера с Magic_1, один скрипт с Magic_2, другой скрипт с Magic_3.

Чтобы советник отличал ордера в цикле перебирающем все ордера делается проверка

if(OrderMagicNumber()==Magic_1) - сделать что-то
if(OrderMagicNumber()==Magic_2) - сделать что-то другое
if(OrderMagicNumber()==Magic_3) - сделать еще что-то

рефреш не помешает перед OrdeClose() и при открытии перед расчетом сл, тп и OrderSend(), но он там есть


Вообще-то если за пипсами охотиться, то рефреш перед проверкой условия делать, а то условие выполниться, а цена ихзменится после рефреша

 
Первое спасибо!
Значит вместо OrderProfit()>=DesirePips*Point делаем типа OrderProfit()>=DesirePips*Price1Pip где Price1Pip вычисленная стоимость 1 п.

Кстати, а Клозер у меня работал нормально :) поскольку у европейских валют при "по маленькой" - 1п=1уй (примерно :). Я при проверке и не заметил, что что-то не так.

По поводу магии: нашел, куда ставить

   ticket=OrderSend(Symbol(),OP_BUY,Stake,
                    NormalizeDouble(MarketInfo(Symbol(),MODE_ASK),Dgts), 
                    Slippage,
                    NormalizeDouble(SL,Dgts),
                    NormalizeDouble(TP,Dgts),
                    "",123456789,0,CLR_NONE);
Вопрос - для каждой позы нужен свой "магик" или можно "один для всех"? открываемых скриптом.

Вопрос 2 - Если скрипт открывает не позу, а ордер BuyStop, после того как ордер превратится в открытую позицию, его "магик" изменится?
 
Первый вопрос - на Ваше усмотрение. Теоретически каждому ордеру можно присваивать уникальный Магик, который будет в себе нести:
  • идентификатор кода
  • идентификатор условия открытия ордера
  • идентификатор тайм-фрейма
    и так далее

По второму - однажды присвоенный MagicNumber стается неизменным, даже если ордер был переоткрыт сервером там, где не начисляются свопы, а производятся переоткрытия.
 
Bookkeeper:
Первое спасибо!
Значит вместо OrderProfit()>=DesirePips*Point делаем типа OrderProfit()>=DesirePips*Price1Pip где Price1Pip вычисленная стоимость 1 п.
Если хочется вычислять стоимость одного пункта в зависимости от символа и лота. Проще в пунктах посчитать Buy: Bid-OrderOpenPrice() и Sell: OrderOpenPrice()-Ask, еще нормализовать обязательно, а то будет иногда +- пункт.
 
To Integer: Спасибо, от лота обязательно, он у меня постоянно "плавает", а вот с пересчетом в дюнюшку - думаю можно будет себя послать. На скальпе пересчет и даст дикую точность в +-1п, нет смысла.

To Rosh: Спасибо, понял: был BuyStop c Магиком, после пробоя будет открытая поза с тем же Магиком. Оч приятно.
Про дробность номера уже прикидывал, но оставил "на потом". Пока могу отслеживать только одну пару, не актуально, но ... задел сделаю.
Кстати - приятного индюка выложили (Spearman), спасибо. Я слепил Fan-текстовика по-быстрому, вставил в канализатор на Н1 и Н4. Может идея пригадится кому из скальпирующих - хорошо видно попадание в зоны откатов на разных ТФ.

//+------------+-----------------------------------------------------+
//| v.04.03.07 |                                       FanRS_txt.mq4 |
//+------------+              Spearman,                              |
//|            |              Rosh                                   |
//|            |              И примазавшийся к ним                  |
//|            |              Bookkeeper, 2007, yuzefovich@gmail.com |
//+------------+-----------------------------------------------------+
#property copyright ""
#property link      ""
//----
//#property indicator_separate_window
#property indicator_chart_window
#property copyright ""
#property link      ""
/********************************************************************/ 
extern string Prefix = "FanRS"; 
extern int    rangeN=14;
extern int    CalculatedBars=100;
extern int    Maxrange=30;
/********************************************************************/ 
string FontName="Courier New"; 
int    FontSize=10; 
bool   First=true;
int    prevBars=0;
string GlobName;
string RowName[4] = { "Rosh-Spearman M5", 
                      "Rosh-Spearman M15", 
                      "Rosh-Spearman H1", 
                      "Rosh-Spearman H4" 
};
/********************************************************************/ 
string LabelName(int i) 
{ return(GlobName+"TxtLbl_"+i); } 
/********************************************************************/ 
void UpdateTxtInLabel(int i, string p, double d, color c) { double a;
a=NormalizeDouble(d*100,1); string s=p+" "; if(MathAbs(d)<10) s=s+" "; 
if(d>0) s=s+"+"; s=s+DoubleToStr(a,1);
ObjectSetText(LabelName(i), s, FontSize, FontName, c); return; } 
/********************************************************************/ 
void deinit() { int N,i; string SStr,NO;
N=ObjectsTotal(); for(i=N;i>=0;i--) {
NO=ObjectName(i); SStr=StringSubstr(NO,0,StringLen(GlobName));
if(SStr==GlobName) ObjectDelete(NO); } return; }
/********************************************************************/ 
void init() { string s; GlobName=Prefix+"_"+Symbol()+"_"+Period()+"_";
for(int j=0; j<5; j++) { s=LabelName(j); 
ObjectCreate (s,OBJ_LABEL,0,0,0); 
ObjectSet    (s,OBJPROP_XDISTANCE,5*FontSize/10); 
ObjectSet    (s,OBJPROP_YDISTANCE,j*16*FontSize/10+3*FontSize/10);
ObjectSet    (s,OBJPROP_CORNER,1); 
ObjectSet    (s,OBJPROP_BACK,false); 
ObjectSetText(s," ",FontSize,FontName,Black); }
ObjectSetText(LabelName(0),"Fan Rosh-Spearman",FontSize,FontName,Black);
 return; }
/********************************************************************/ 
void start() { double prevRS5, prevRS15, prevRS60, prevRS240;
double RS5, RS15, RS60, RS240; color t, r=Red, g=Green, b=Blue;
RS5=iCustom(NULL,PERIOD_M5,"SpearmanRankCorr",
            rangeN,CalculatedBars,Maxrange,0,0);
prevRS5=iCustom(NULL,PERIOD_M5,"SpearmanRankCorr",
                rangeN,CalculatedBars,Maxrange,0,1);
t=b; if(RS5>prevRS5) t=g; if(RS5<prevRS5) t=r;
UpdateTxtInLabel(1,"M5 ",RS5,t);
RS15=iCustom(NULL,PERIOD_M15,"SpearmanRankCorr",
             rangeN,CalculatedBars,Maxrange,0,0);
prevRS15=iCustom(NULL,PERIOD_M15,"SpearmanRankCorr",
                 rangeN,CalculatedBars,Maxrange,0,1);
t=b; if(RS15>prevRS15) t=g; if(RS15<prevRS15) t=r;
UpdateTxtInLabel(2,"M15",RS15,t);
RS60=iCustom(NULL,PERIOD_H1,"SpearmanRankCorr",
             rangeN,CalculatedBars,Maxrange,0,0);
prevRS60=iCustom(NULL,PERIOD_H1,"SpearmanRankCorr",
                 rangeN,CalculatedBars,Maxrange,0,1);
t=b; if(RS60>prevRS60) t=g; if(RS60<prevRS60) t=r;
UpdateTxtInLabel(3,"H1 ",RS60,t);
RS240=iCustom(NULL,PERIOD_H4,"SpearmanRankCorr",
             rangeN,CalculatedBars,Maxrange,0,0);
prevRS240=iCustom(NULL,PERIOD_H4,"SpearmanRankCorr",
                 rangeN,CalculatedBars,Maxrange,0,1);
t=b; if(RS240>prevRS240) t=g; if(RS240<prevRS240) t=r;
UpdateTxtInLabel(4,"H4 ",RS240,t);
 return; }
За код извиняюсь - думал не сильно.
Но помогает не мельтишить, не переключаться излишне между окнами.
И вообще, если кто не обратил еще внимания на индюшку - по-моему стоит (особенно собратьям-Чайникам, очень логично и понятно).
Причина обращения: