Спред между двумя фьючерсами - страница 3

 
Dmi3:

Хороший результат, поздравляю.

Вы умеете входить в арбитражную сделку в 10.00.00?

К сожалению нет, а то бы результат был в разы больше

На графике видно, что далеко не 10-00, а доход получился 141 пункт на 1 пару


 
prostotrader:

К сожалению нет, а то бы результат был в разы больше

На графике видно, что далеко не 10-00, а доход получился 141 пункт на 1 пару


Отдельная сделка не интересна. Интересна эквити, но по календарям эквити строить сложно, для меня, с моим уровнем кодинга. Для вас наверное нет, покажите эквити календаря по GOLD хотя бы за этот год? Я пытался торговать календарь на GOLD и ушел с этой темы. Слишком резкие движения БА, хотя может быть я попал как раз на период безоткатного роста с 1500 до 2000, но желание пока отпало :(

 
Dmi3:

Отдельная сделка не интересна....

Да? Давайте посчитаем...

141 пункт * 62 пары * 7,558 руб(за пункт) = 66072.036 руб. (грязными, без учета комиссий)

Календарь торговать очень не просто, действительно можно сильно "вперется", вот чтобы

этого не произошло нужна хорошая и точная история и, конечно, реал-тайм данные...

Ну, и обязательно, внимательно следить за новостями, особенно политическими.

 
prostotrader:

Да? Давайте посчитаем...

141 пункт * 62 пары * 7,558 руб(за пункт) = 66072.036 руб. (грязными, без учета комиссий)

То есть эквити по календарям у вас тоже нет? Возможно у вас есть свой метод, существенно отличный от моего. В  моем методе следить за новостями совсем не надо. :)

Поразмышляю на эту тему, спасибо!

Я календари торгую только за 2 недели до экспирации и прекращаю за 1 день до экспирации.

 
iiivasyaiii:

Простотрейдер, большое спасибо вам за совет! Решение интересное, сейчас попробую, потом отпишусь.

//+------------------------------------------------------------------+
//|                                                       Spread.mq5 |
//|                                     Copyright 2020, prostotrader |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015-2020, prostotrader"
#property link      "http://www.mql5.com"
#property version   "1.035"
//
#property indicator_separate_window

#property indicator_buffers 2
#property indicator_plots   2

//--- plot Label1
#property indicator_label1  "Hi spread"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Label2
#property indicator_label2  "Low spread"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- Levels
#property indicator_level1 0
#property indicator_level2 0
#property indicator_level3 0
//---
struct DATA_TIME
{
  datetime time;
  double hi_value;
  double low_value;
};
//
string sec_symbol;
//
input string   FutName   = "BR-11.20";             //Имя второго фьючерса 
input int      NMonth    = 3;                      //Разница между фьючерсами (мес)
input int      BrMonth   = 1;                      //Разн. между фьюч.(мес) Brent(RVI, CL)
input bool     AutoDate  = false;                  //Автоматическое начало расчета 
input datetime StartData = D'2020.07.01 19:05:00'; //Дата начала расчёта индикатора
input bool     Hyst      = true;                   //Использовать историю
input bool     UseOtstup = true;                   //Использовать Мин./Мах индикатора
input double   Otstup    = 30;                     //Мин./Мах индикатора

//--- indicator buffers
double HiBuff[], LowBuff[];
double max_value; 
double min_value;
double mid_value;
ulong  mid_cnt;
//---
datetime start_time;
datetime end_time;
//
datetime time_array[];
bool pr_book, sec_book;
MqlTick pr_ticks[], sec_ticks[];
int pr_cnt, sec_cnt;
//
int next_month;
int event_cnt;
DATA_TIME data_time[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
bool CheckOneMonth(const string a_symb)
{
  if((StringFind(a_symb,"BR-") == 0) || (StringFind(a_symb, "CL-") == 0) ||
     (StringFind(a_symb, "GLD-") == 0) || (StringFind(a_symb, "RVI-") == 0) ||
     (StringFind(a_symb, "UINR-") == 0) || (StringFind(a_symb, "Al-") == 0) ||
     (StringFind(a_symb, "Zn-") == 0) || (StringFind(a_symb, "Nl-") == 0) ||
     (StringFind(a_symb, "Co-") == 0) || (StringFind(a_symb, "NG-") == 0))
  {
    return(true);
  }
  return(false);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
datetime GetStartTime(const string a_symb)
{
  int str_tire = StringFind(a_symb, "-");
  int str_tochka = StringFind(a_symb, ".", str_tire);
  int str_size = StringLen(a_symb);
  if((str_tire > 0) && (str_tochka > 0) && (str_size > 0))
  {
    string str_month = StringSubstr(a_symb, str_tire + 1, str_tochka - str_tire - 1);
    string str_year = StringSubstr(a_symb, str_tochka + 1, str_size - str_tochka - 1);
    long a_month = StringToInteger(str_month);
    long a_year = StringToInteger(str_year); 
    string pr_symb;
    a_month = a_month - 1;
    if(a_month == 0)
    {
      a_month = 12;
      a_year = a_year - 1; 
    }
    str_year = IntegerToString(a_year); 
    str_month = IntegerToString(a_month);
    pr_symb = StringSubstr(a_symb, 0, str_tire + 1) + str_month + "." + str_year;
    if(SymbolSelect(pr_symb, true) == true)
    {
      Print(__FUNCTION__, ": Предыдудищий фьючерс ", pr_symb);
      SymbolSelect(pr_symb, false);
      return(datetime(ulong(SymbolInfoInteger(pr_symb, SYMBOL_EXPIRATION_TIME)) + 60 * 20));
    }  
  }
  return(datetime(0));
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
  mid_value = 0;
  mid_cnt = 0;
  if(TerminalInfoInteger(TERMINAL_BUILD) < 2560)
  {
    Print( "Версия билда терминала должна быть не менее 2560!" );
    return(INIT_FAILED);
  }
  if(Period() != PERIOD_M1)
  {
    Print("Период графика должен быть М1!");
    return(INIT_FAILED);
  }
  event_cnt = 0;
  next_month = NMonth;
  max_value = -DBL_MAX; 
  min_value = DBL_MAX;
//---
  if(CheckOneMonth(Symbol())== true)
  {
    next_month = BrMonth;
  }
  else
  {
    next_month = NMonth; 
  }
  sec_symbol = FutName;
  
if(CheckOneMonth(sec_symbol)== true)
  {
    if(next_month == 3)
    { 
      Alert("Продолжительность фючерсов не совпадает!");
      return(INIT_FAILED);
    }  
  } 
  
  ResetLastError();
  if(!SymbolInfoInteger(sec_symbol, SYMBOL_SELECT))
  {
    if(GetLastError() != ERR_MARKET_UNKNOWN_SYMBOL)
    {
      SymbolSelect(sec_symbol, true);
    }
    else
    {
      Print(__FUNCTION__, ": Неизвестный символ - ", sec_symbol);
      return(INIT_FAILED);
    }    
  }
  end_time = datetime(SymbolInfoInteger(Symbol(), SYMBOL_EXPIRATION_TIME));
  if(AutoDate == true)
  {
    start_time = GetStartTime(Symbol());
  }
  else
  {
    start_time = StartData;
  }  
//---  
  IndicatorSetInteger(INDICATOR_DIGITS, 0);
  IndicatorSetString(INDICATOR_SHORTNAME, "Spread");
  SetIndexBuffer(0, HiBuff, INDICATOR_DATA);
  ArraySetAsSeries(HiBuff, true);
  PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
  SetIndexBuffer(1, LowBuff, INDICATOR_DATA);
  ArraySetAsSeries(LowBuff, true);
  PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
  IndicatorSetInteger(INDICATOR_LEVELCOLOR, 0, clrRed);
  IndicatorSetInteger(INDICATOR_LEVELCOLOR, 1, clrBlue);
  IndicatorSetInteger(INDICATOR_LEVELCOLOR, 2, clrYellow); 
  IndicatorSetInteger(INDICATOR_LEVELSTYLE, STYLE_DOT);
  IndicatorSetInteger(INDICATOR_LEVELWIDTH, 1);
//--- Bars on chart
  if(Hyst == true)
  {
    int cnt = 0;
    int result = 0;
    int res = 0;
    int a_bars = 0;
    while ((result <= 0) && (cnt < 100)) 
    {
      result = CopyTime(Symbol(), PERIOD_M1, start_time, end_time, time_array);
      if(result == a_bars) break;
      cnt++;   
    }
    if(result > 0)
    {
      cnt = 0;
      result = 0;
      while ((result <= 0) && (cnt < 100)) 
      {
        result = CopyTicksRange(Symbol(), pr_ticks, COPY_TICKS_INFO, ulong(start_time) * 1000, ulong(end_time) * 1000);
        cnt++;
      }
      if(result > 0)
      {
        pr_cnt = result;
        cnt = 0;
        result = 0;
        while ((result <= 0) && (cnt < 100)) 
        {
          result = CopyTicksRange(sec_symbol, sec_ticks, COPY_TICKS_INFO, ulong(start_time) * 1000, ulong(end_time) * 1000);
          cnt++;
        }
        if(result > 0)
        {
          sec_cnt = result;
          cnt = 0;
          ArrayResize(data_time, a_bars);
          ZeroMemory(data_time);
          for(int i = 0; i < a_bars; i++)
          {
            if(ulong(time_array[i])>= ulong(start_time))
            {
              data_time[cnt].time = time_array[i]; 
              cnt++;
            }
          }
          if(cnt > 0)
          {
            a_bars = cnt;
            ArrayResize(data_time, a_bars);
            int pr_pos = 0;
            int sec_pos = 0;
            bool is_found;
            int pr_mem = 0;
            int sec_mem = 0;
//---            
            for(int i = 0; i < a_bars; i++)
            {
              data_time[i].hi_value = EMPTY_VALUE;
              data_time[i].low_value = EMPTY_VALUE;
              is_found = false;
              while(pr_pos < pr_cnt) 
              {
                if((ulong(data_time[i].time) <= ulong(pr_ticks[pr_pos].time)) &&
                   (ulong(data_time[i].time) + 60 > ulong(pr_ticks[pr_pos].time)))
                {
                  pr_mem = pr_pos;
                  while(sec_pos < sec_cnt) 
                  {
                    if((ulong(data_time[i].time) <= ulong(sec_ticks[sec_pos].time)) &&
                       (ulong(data_time[i].time) + 60 > ulong(sec_ticks[sec_pos].time)))
                    {
                      is_found = true;
                      sec_mem = sec_pos;
                      if((sec_ticks[sec_pos].bid > 0.0) && (pr_ticks[pr_pos].ask > 0.0) &&
                         (sec_ticks[sec_pos].ask > 0.0) && (pr_ticks[pr_pos].bid > 0.0))
                      {
                        data_time[i].hi_value = sec_ticks[sec_pos].bid - pr_ticks[pr_pos].ask;
                        data_time[i].low_value = sec_ticks[sec_pos].ask - pr_ticks[pr_pos].bid;
                      }
                      break;
                    }
                    sec_pos++;
                  }
                  break;
                }
                pr_pos++;
              }
              pr_pos = pr_mem;
              sec_pos = sec_mem;
            }
          }
        }
        else
        {
          Alert("Не получены тики по второму символу!");
          return(INIT_FAILED);
        }
      }
      else
      {
        Alert("Не получены тики по первому символу!");
        return(INIT_FAILED);
      }
    }
    else
    {
      Alert("Не получены бары по символу!");
      return(INIT_FAILED);
    }
  }
//--- Books ---    
  pr_book = MarketBookAdd(Symbol());
  sec_book = MarketBookAdd(sec_symbol);
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
// Custom indicator DeInit function                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  if(pr_book == true) MarketBookRelease(Symbol());
  if(sec_book == true) MarketBookRelease(sec_symbol);
  if(reason == REASON_INITFAILED)
  {
    Print("Индикатор удалён! Причина - ошибка инициализации.");
    ChartIndicatorDelete(0, 1, "Spread"); 
  }
}
//+------------------------------------------------------------------+
//| Custom indicator On book event function                          |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
  if((symbol == Symbol()) || (symbol == sec_symbol))
  {
    datetime a_time[];
    double a_open[];
    double a_high[];
    double a_low[];
    double a_close[];
    long a_t_vol[];
    long vol[];
    int a_spread[];
    OnCalculate(event_cnt, event_cnt, a_time, a_open, a_high, a_low, a_close, a_t_vol, vol, a_spread); 
  }
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate( const int rates_total,
                 const int prev_calculated,
                 const datetime &time[],
                 const double &open[],
                 const double &high[],
                 const double &low[],
                 const double &close[],
                 const long &tick_volume[],
                 const long &volume[],
                 const int &spread[] )
{
  if(prev_calculated == 0)
  {
    ArrayInitialize(HiBuff, EMPTY_VALUE);
    ArrayInitialize(LowBuff, EMPTY_VALUE);
    if(Hyst ==true)
    {
      ArraySetAsSeries(time, true);
      int pos = 0;
      int mem_pos = 0;
      bool is_found;
      for(int i = rates_total - 1; i > 0; i--)
      {
        is_found = false;
        while(pos < ArraySize(data_time))
        {
          if(time[i] == data_time[pos].time)
          {
            is_found = true;
            mem_pos = pos;
            if((data_time[pos].hi_value != EMPTY_VALUE) && (data_time[pos].low_value != EMPTY_VALUE))
            {
              HiBuff[i] = data_time[pos].hi_value/Point();
              LowBuff[i] = data_time[pos].low_value/Point();
              if(HiBuff[i] > max_value) max_value = HiBuff[i];
              if(LowBuff[i] < min_value) min_value = LowBuff[i];
               mid_value = mid_value * mid_cnt + (min_value + max_value)/2;
               mid_cnt++; 
               mid_value = mid_value/mid_cnt;
            }
            else
            {
              if(i < rates_total - 1)
              {
                HiBuff[i] = HiBuff[i+1];
                LowBuff[i] = LowBuff[i+1];
              }  
            }
            break;
          }
          pos++;
        }
        if(is_found == false)
        {
          pos = mem_pos;
        }
      }
    }
  }
  else
  {
    double sec_ask = SymbolInfoDouble(sec_symbol, SYMBOL_ASK);
    double sec_bid = SymbolInfoDouble(sec_symbol, SYMBOL_BID);
    double pr_ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
    double pr_bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
    if((sec_ask> 0) && (sec_bid > 0) && (pr_ask > 0) && (pr_bid > 0))
    {
      double hi_val = (sec_bid - pr_ask)/Point();
      double low_val = (sec_ask - pr_bid)/Point();
      if(hi_val > max_value) max_value = hi_val;
      if(low_val < min_value) min_value = low_val;
      HiBuff[0] = hi_val;
      LowBuff[0] = low_val;
      mid_value = mid_value * mid_cnt + (min_value + max_value)/2;
      mid_cnt++; 
      mid_value = mid_value/mid_cnt;
    }
    else
    {
      HiBuff[0] = HiBuff[1];
      LowBuff[0] = LowBuff[1];
    }
  }
  IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, max_value);
  IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, min_value);
  IndicatorSetDouble(INDICATOR_LEVELVALUE, 2, mid_value);
  if(UseOtstup == true)
  {
    IndicatorSetDouble(INDICATOR_MAXIMUM, max_value + Otstup);
    IndicatorSetDouble(INDICATOR_MINIMUM, min_value - Otstup);
  }  
//--- return value of prev_calculated for next call
   event_cnt = rates_total;
//--- 
  return(rates_total);
}

//+------------------------------------------------------------------+

Но на моем компе есть проблема

https://www.mql5.com/ru/forum/351487

Просьба запустить на реале на BR-11.20
Просьба запустить на реале на BR-11.20
  • 2020.09.18
  • www.mql5.com
Пишу индикатор с использованием функции CopyTicksRange(); Получаю кастрированные данные https://www.mql5...
 
prostotrader:

Но на моем компе есть проблема

https://www.mql5.com/ru/forum/351487

Простотрейдер, большое спасибо за код! У меня тоже открываха.

LD      0       12:49:16.265    Proverka-CopyTicksRange (BR-11.20,M1)   Start time = 2020.07.01 19:05:00
FK      0       12:49:16.265    Proverka-CopyTicksRange (BR-11.20,M1)   End time = 2020.11.02 18:45:00
KO      0       12:49:16.265    Proverka-CopyTicksRange (BR-11.20,M1)   Time now = 2020.09.21 08:49:16
EI      0       12:49:16.265    Proverka-CopyTicksRange (BR-11.20,M1)   Bars last time = 2020.09.18 23:49:00
QD      0       12:49:16.265    Proverka-CopyTicksRange (BR-11.20,M1)   Last tick time = 2020.09.18 23:57:33
 
prostotrader:

Да? Давайте посчитаем...

141 пункт * 62 пары * 7,558 руб(за пункт) = 66072.036 руб. (грязными, без учета комиссий)

Календарь торговать очень не просто, действительно можно сильно "вперется", вот чтобы

этого не произошло нужна хорошая и точная история и, конечно, реал-тайм данные...

Ну, и обязательно, внимательно следить за новостями, особенно политическими.

62 пары?! Как вы смогли столько найти? У меня даже самых смелых прикидок на 62 вариации не хватает))

 
iiivasyaiii:

62 пары?! Как вы смогли столько найти? У меня даже самых смелых прикидок на 62 вариации не хватает))

:) 62*2 КОНТРАКТА gold

 
iiivasyaiii:

Простотрейдер, большое спасибо за код! У меня тоже открываха.

Его нужно подправить, чтобы убрать ошибку...

Сейчас нет времени, сделаю чуть позже

Кстати, в функции GetStartTimе

нужно заменить строку

a_month = a_month - 1;

на

a_month = a_month - next_month;

 
prostotrader:

:) 62*2 КОНТРАКТА gold

Я конечно очень извиняюсь, если задаю слишком "интимные" вопросы, но привык вникать в детали.

Что именно вы сарбитражили 17-го сентября, мне не понятно.

Если GOLD-12.20 - GOLD-9.20, то GOLD-9.20 c 12.30 17/09 не меняется в цене, так как уже определена расчетная цена исполнения контракта по спецификации, таким образом у вас получается не арбитраж, а простой и незамысловатый контр-тренд GOLD-12.20.



Если GOLD-3.21-GOLD-12.20, то как, черт возьми, вы протащили 62 контракта на вход + 62 контракта на выход = 124 контракта, при том, что общий объем торгов по GOLD-3.21 за 17.09 составил по данным биржи всего 306 контрактов?


В итоге вариант два не представляется возможным, тогда остается вариант номер один. Но ведь это совсем не арбитраж, вы же понимаете?