Spread between two futures - page 3

 
Dmi3:

Good result, congratulations.

Do you know how to enter an arbitrage trade at 10.00.00?

Unfortunately no, otherwise the result would have been much bigger.

On the chart you can see that it is far from 10-00 and the profit is 141 pips per 1 pair


 
prostotrader:

Unfortunately not, otherwise the result would have been many times bigger

On the chart you can see that it is far from 10-00, and the profit turned out 141 points per 1 pair


Individual trades are not interesting. Equity is of interest here but it is difficult to trace the equities according to calendars at my coding level. Probably not for you, show me the equity of the GOLD calendar at least for this year? I tried to trade the calendar on GOLD and walked away from that topic. Too abrupt BA movements, though maybe I hit just the right period of a no-holds-barred rise from 1500 to 2000, but so far I've given up the urge :(

 
Dmi3:

Separate deal not interesting....

Yes? Let's do the math...

141 points * 62 pairs * 7,558 rubles(per point) = 66072.036 rubles. (dirty, excluding commissions)

It's not easy to trade the calendar, you can really screw up.

to prevent this you need a good and accurate history and of course, real-time data...

And, of course, you have to keep a close eye on the news, especially political ones.

 
prostotrader:

Yes? Let's do the math...

141 points * 62 pairs * 7.558 roubles(per point) = 66072.036 roubles. (dirty, not including commissions)

So you don't have equity on the calendars either? Perhaps you have your own method, significantly different from mine. In my method you don't need to follow the news at all. :)

I will think about it, thanks!

I only trade calendars 2 weeks before expiry and stop 1 day before expiry.

 
iiivasyaiii :

Simple trader, thank you very much for your advice! The solution is interesting, now I'll try it, then I'll unsubscribe.

 //+------------------------------------------------------------------+
//|                                                       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);
}

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

But there is a problem on my computer

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

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

But there is a problem on my computer

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

Prostotrader, thanks so much for the code! I have an opener as well.

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:

Yes? Let's do the math...

141 points * 62 pairs * 7.558 roubles(per point) = 66072.036 roubles. (dirty, excluding commissions)

It's not easy to trade the calendar, you can really screw up.

to prevent this you need a good and accurate history and of course, real-time data...

And of course one has to watch closely the news, especially political ones.

62 pairs?! How did you manage to find so many? I don't have even the boldest guess at 62 variations))

 
iiivasyaiii:

Sixty-two pairs?! How did you manage to find so many? I don't have even the boldest estimate for 62 variations))

:) 62*2 CONTRACT gold

 
iiivasyaiii:

Prostotrader, thank you very much for the code! I have an opener as well.

It needs to be tweaked to remove the error...

No time right now, will do it a bit later

By the way, in the GetStartTime function

you have to replace the line

a_month = a_month - 1;

to

a_month = a_month - next_month;

 
prostotrader:

:) 62*2 CONTRACT gold

I certainly apologise if I am asking too "intimate" questions, but I am used to getting into details.

What exactly were you sarbitrating on September 17th is not clear to me.

If GOLD-12.20-GOLD-9.20, then GOLD-9.20 from 12.30 on 17/09 does not change in price, as the settlement price of the contract has already been determined by the specification, so you do not have arbitrage, but a simple and uncomplicated counter-trend GOLD-12.20.



If GOLD-3.21-GOLD-12.20, how the hell did you get 62 contracts to enter + 62 contracts to exit = 124 contracts, despite the fact that the total volume of GOLD-3.21 trading on 17.09 was only 306 contracts according to exchange data?


As the result Variant two is not possible, Variant one is. But this is not arbitrage at all, do you understand?

Reason: