Библиотеки: File Mapping без DLL - страница 11

 
fxsaber:

Спасибо автору за библиотеку!

Сварганил функции для передачи любых данных. Ниже скрипт показывает их работу на примере тиков


Результат


Супер! По аналогии с Вашим кодом упростил для себя использование библиотеки.

 
Пример передачи цен для MT4

Forum on trading, automated trading systems and testing trading strategies

NamedPipes for metatrader 4

fxsaber, 2017.11.30 14:18

Exchange_Data.mqh

#include <MemMapLib.mqh>
#include <TypeToBytes.mqh>

template <typename T>
class EXCHANGE_DATA
{
private:
  CMemMapFile* FileMemory;

public:  
  // Выделяет память заданной длины под данные 
  EXCHANGE_DATA( const int Amount, const bool ModeCreate = false, string FileName = "Local\\test" )
  {
//    FileName += _Symbol;
    
    this.FileMemory = new CMemMapFile;
      
    if (this.FileMemory.Open(FileName, sizeof(T) * Amount + sizeof(int) + HEAD_MEM, ModeCreate ? modeCreate : modeOpen) != 0)
    {
      Alert("FileMemory.Open - ERROR!");
      
      delete &this;
    }
  }
  
  ~EXCHANGE_DATA( void )
  {
    this.FileMemory.Close();
    
    delete this.FileMemory;
  }

  // Записывает данные в память
  void DataSave( const T &Data[], const bool FromBegin = true  ) const
  {
    const int Size = ::ArraySize(Data) * sizeof(T);
    uchar Bytes[];
    
    _ArrayCopy(Bytes, _R(Size).Bytes);              // Записали количество  
    _ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // Записали данные
  
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        this.FileMemory.Write(Bytes, ::ArraySize(Bytes)); // Сбросили все в память
    
    return;
  }
  
  // Считывает данные из памяти
  int DataLoad( T &Data[], const bool FromBegin = true ) const
  {
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        uchar Bytes[];
          
        this.FileMemory.Read(Bytes, sizeof(int));  // Прочли из памяти количество данных        
        this.FileMemory.Read(Bytes, _R(Bytes)[0]); // Получили сами данные
  
        _ArrayCopy(Data, Bytes);              // Сбросили данные в массив
    
    return(::ArraySize(Data));
  }  
};


PriceGiver.mq4

#property strict

#include "Exchange_Data.mqh"

#define AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT, true);

const bool Init = EventSetMillisecondTimer(100);

void OnTimer( void )
{
  static MqlTick Ticks[1];
  
  if (SymbolInfoTick(_Symbol, Ticks[0]))
    ExchangeTicks.DataSave(Ticks);
}


PriceTaker.mq4

#property strict

#include "Exchange_Data.mqh"

#define AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT);

const bool Init = EventSetMillisecondTimer(100);

#define TOSTRING(A) (#A + " = " + (string)(A) + " ")

void OnTimer( void )
{  
  static MqlTick PrevTick = {0};  
  MqlTick Ticks[];
  
  if ((ExchangeTicks.DataLoad(Ticks) > 0) &&
      ((Ticks[0].bid != PrevTick.bid) || (Ticks[0].ask != PrevTick.ask)))
  {
    Print(TOSTRING(Ticks[0].time) + TOSTRING(Ticks[0].bid) + TOSTRING(Ticks[0].ask));
    
    PrevTick = Ticks[0];
  }
}


Run PriceGiver.ex4 and PriceTaker.ex4.


Result

2017.11.30 15:13:55.101 Expert PriceGiver EURUSD,M1: removed
2017.11.30 15:13:55.091 PriceGiver EURUSD,M1: uninit reason 1
2017.11.30 15:13:51.006 Expert PriceTaker GBPAUD,M1: removed
2017.11.30 15:13:50.996 PriceTaker GBPAUD,M1: uninit reason 1
2017.11.30 15:13:49.168 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:48.838 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18489 
2017.11.30 15:13:48.186 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:47.751 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:42.178 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18485 Ticks[0].ask = 1.18489 
2017.11.30 15:13:41.633 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:37.588 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:30 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:36.175 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:28 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:30.717 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:23 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:29.514 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:22 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:27.324 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.1848 Ticks[0].ask = 1.18484 
2017.11.30 15:13:26.994 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:26.012 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.584 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:25.254 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:16 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.147 PriceTaker GBPAUD,M1: initialized
2017.11.30 15:13:24.049 Expert Sparring\PriceTaker GBPAUD,M1: loaded successfully
2017.11.30 15:13:21.157 PriceGiver EURUSD,M1: initialized
2017.11.30 15:13:19.617 Expert Sparring\PriceGiver EURUSD,M1: loaded successfully
 

В библиотеке небольшая ошибочка в методе CMemMapFile::Open.  Он должен возвращать хэндл файла (тип HANDLE64), но вместо этого возвращает 0 либо код ошибки.

Кроме того, крайне нерационально реализованы чтение и запись.  В методах CMemMapApi::Write и CMemMapApi::Read  зачем-то сделано двойное перекопирование данных (причём байты перебираются в цикле!), и вдобавок файл перезаписывается/перечитывается целиком, хотя требуется лишь заданный кусок.

В общем я привёл их в нормальный вид, лишнее закомментировано :

//------------------------------------------------------------------    Write
int CMemMapApi::Write(HANDLE64 hmem, const uchar &buf[], DWORD pos, int sz, DWORD &err) // запись в память указанное число байт
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // если не открыт
  DWORD size=GetSize(hmem, err);  if (pos+sz>size) { UnViewFile(view);  return(-2); }; // если размер меньше, то выходим
  /*    
  uchar src[];  ArrayResize(src, size);  memcpyX(src, view, size); // взяли байтбуфер
  for(int i=0; i<sz; i++) src[pos+i+HEAD_MEM]=buf[i]; // записали в память
  memcpyX(view, src, size); // скопировали обратно
  */    
  memcpyX(view+HEAD_MEM+pos, buf, sz);  
  UnViewFile(view); // закрыли просмотр
  return(0); // вернули ОК
}
//------------------------------------------------------------------    Read
int CMemMapApi::Read(HANDLE64 hmem, uchar &buf[], DWORD pos, int sz, DWORD &err) // чтение из памяти указанное число байт
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // если не открыт
  DWORD size=GetSize(hmem, err); // получили размер
  /*    
  uchar src[];  ArrayResize(src, size);  memcpyX(src, view, size); // взяли байтбуфер
  ArrayResize(buf, sz);
  int i=0; for(i=0; i<sz && pos+i<size; i++) buf[i]=src[pos+i+HEAD_MEM]; // читаем байты
  */    
  sz= fmin(sz, size-pos);
  ArrayResize(buf, sz);
  memcpyX(buf, view+HEAD_MEM+pos, sz);
  UnViewFile(view); // закрыли просмотр
  return sz; // число скопированных байт
}
Чтобы первая функция компилировалась, нужно расставить const у массивов в функциях memcpyX и memcpy , которые автор не удосужился проставить.
 

Ошибка при копировании больших объемов, из-за нуля, который передается в dwMaximumSizeHigh

        if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, 0, size + HEAD_MEM, path); // создаем объект памяти

Поправил так:

if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, size + HEAD_MEM, size + HEAD_MEM, path); // создаем объект памяти


Такой объем - 6 мб, передает без проблем:

void OnStart()
{
   int bars = Bars(_Symbol, _Period);
   MqlRates rates[]; 
   ArraySetAsSeries(rates, true); 
   CopyRates(NULL, 0, 0, bars, rates); 

   int size = ArraySize(rates) * sizeof(MqlRates);
   
   uchar data[];
   _ArrayCopy(data, rates);
   
   CMemMapFile *hmem = new CMemMapFile();
   hmem.Open("test", size, modeCreate);
   hmem.Write(data, size);
   hmem.Close(); 
   delete hmem;

   Print(size);
}


 
pushdib:

Поправил так:

правильно передавать туда старшие 4 байта 8-байтного размера.

 

Ок, в проге на C# теперь имеем все рэйты и можем с помощью LINQ отлично все что нужно анализировать.

Но есть такой вопрос, а как лучше организовать механизм команд между терминалом и приложением.

От терминала: новая свеча, новые рэйты - забери файл

От приложения: расчет завершен, забери  результат (нарисуй на графике, открой сделку)


У кого-нибудь есть опыт подобной реализации взаимодействия терминала и кода?

 
pushdib:

Ок, в проге на C# теперь имеем все рэйты и можем с помощью LINQ отлично все что нужно анализировать.

Но есть такой вопрос, а как лучше организовать механизм команд между терминалом и приложением.

От терминала: новая свеча, новые рэйты - забери файл

От приложения: расчет завершен, забери  результат (нарисуй на графике, открой сделку)


У кого-нибудь есть опыт подобной реализации взаимодействия терминала и кода?

Сделал все это через пайп - работает как часы.
 
Это просто гениально, спасибо за труды! -)). Пришлось заодно учить, как работать, с бинарными файлами, но это того стоило. 
 

Подскажите, что делать в такой ситуации.

1. Открыл новый файл в памяти на 100 байт.

2. Записал туда 100 байт.

3. Считал  в другом советнике 100 байт. Все отлично.

4. Как теперь записать в тот же файл 50 или 200 байт ?

Причина обращения: