Как перевезти рабочего эксперта из MT5 в КВИК.

 

Здравствуйте, 

Я давно разрабатываю роботы на MQL5. Хочу перенести часть своих робов на КВИК. Я вообще не люблю эту платформу и никогда для неё не писал. С чего начать обучение? Есть ли тут профессионалы, которые программируют и для КВИКА и занимался переводом экспертов из mql в КВИК?

 
a18psrock:

Здравствуйте, 

Я давно разрабатываю роботы на MQL5. Хочу перенести часть своих робов на КВИК. Я вообще не люблю эту платформу и никогда для неё не писал. С чего начать обучение? Есть ли тут профессионалы, которые программируют и для КВИКА и занимался переводом экспертов из mql в КВИК?

Бросьте эту затею, потому что даже если что-то напишите на QLUA, оттестировать не сможете.

Единственный выход - вывод данных через DDE сервер и транзакции через trans2quik.dll

 
a18psrock:

Здравствуйте, 

Я давно разрабатываю роботы на MQL5. Хочу перенести часть своих робов на КВИК. Я вообще не люблю эту платформу и никогда для неё не писал. С чего начать обучение? Есть ли тут профессионалы, которые программируют и для КВИКА и занимался переводом экспертов из mql в КВИК?

Я вот думал коннектор мт5-квик сделать, чтобы в квик не писать робота. Там ведь тестера нет, его нужно отдельно где то искать.
 

Как-то программировал для квика, держал рядом рвотный пакетик.

Коннектор можно сделать через файл или лучше memory mapping, если квик его потянет

 

Да мост это самый простой вариант. Я когда-то тоже этим баловался, даже написал мост MySQL - QUIK.,

так что если нужно будет обращайтесь (через фриланс) и я вам баксов за 200 сделаю MQL5 - MySQL - QUIK мостик.

P.S. только вот нафига оно вам ?

 
Перевозчика вызывайте - он все перевезет.
 

Alexey VolchanskiyStanislav Dray

Вы все-равно будете писать СВОЁ приложение, человеку не нужно связывать МТ5 с КВИК.

Поэтому самый лучший вариант, это как я описал выше.

Пишем DDE сервер, туда же "цепляем" trans2quik.dll и робот(ы) готов.

unit DdeExlUnt;

interface

uses
  Winapi.Windows, System.Classes, System.Types, Vcl.Forms, Winapi.DdeMl,
  System.SysUtils, System.StrUtils, Vcl.Controls, Winapi.Messages, QTypes;

const
  WM_DDE_ADDQUE = WM_USER + 2;

var
  ServiceName: string;// = 'quikdde';             // DDE server name

  procedure ClearTable(Table: TVariantTable); overload;

type
  TPokeAction = (paAccept, paPass, paReject);
  TDdePokeEvent = procedure(const Topic: string; var Action: TPokeAction) of object;
  TDdeDataEvent = procedure(const Topic: string; Cells: TRect; Data: TVariantTable) of object;

  PDdeQueItem = ^TDdeQueItem;
  TDdeQueItem = packed record
    data: Pointer;
    size: integer;
    sTopic: String;
    sCells: String;
  end;

  TDdeServer = class(TWinControl)
  private
    Inst: Integer;
    ServiceHSz: HSz;
    TopicHSz: HSz;
    fOnPoke: TDdePokeEvent;
    fOnData: TDdeDataEvent;
    fDdeQue: TThreadList;
  protected
    function XLTDecodeV(data: pointer; datasize: integer): TVariantTable;
    function DecodeCellAddr(CellAddr: string): TRect;
    procedure AddQue(var Message: TWMSysCommand); message WM_DDE_ADDQUE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnPoke: TDdePokeEvent read fOnPoke write fOnPoke;
    property OnData: TDdeDataEvent read fOnData write fOnData;
  end;

{var
  DdeServer: TDdeServer;}

//--- Pointer functions ----
function addp(p: Pointer; increment: int64 = 1): Pointer; overload;
function addp(p: Pointer; increment: pointer): Pointer; overload;
function subp(p: Pointer; decrement: int64 = 1): Pointer; overload;
function subp(p: Pointer; decrement: pointer): Pointer; overload;


implementation
uses main;

function CallbackProc(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ;
                      Data: HDDEData; Data1, Data2: DWORD): HDDEData stdcall;
var
  action: TPokeAction;
  sTopic: String;
  P: PDdeQueItem;
  Buff: array[0..255] of WideChar;
begin
  result:= DDE_FNOTPROCESSED;
//---
  case CallType of
    XTYP_CONNECT: result:= 1;
    XTYP_POKE: begin
                 DdeQueryString(QTrader.DdeServer.Inst, HSz1, @Buff,
                                                   sizeof(Buff), CP_WINUNICODE);
                 sTopic:= string(Buff);
                 action:= paPass;
                 if Assigned(QTrader.DdeServer.fOnPoke) then
                   QTrader.DdeServer.fOnPoke(sTopic, action);
//---
                 case action of
                   paAccept: begin
                               DdeQueryString(QTrader.DdeServer.Inst, HSz2,
                                            @Buff, sizeof(Buff), CP_WINUNICODE);
                               New(P);
                               P^.sTopic:= sTopic;
                               P^.sCells:= string(Buff);
                               P^.size:= DdeGetData(Data, nil, 0, 0);
                               GetMem(P^.data, P^.size);
                               DdeGetData(Data, P^.data, P^.size, 0);
//---
                               with QTrader.DdeServer.fDdeQue.LockList do
                               try
                                 add(P);
                               finally
                                 QTrader.DdeServer.fDdeQue.UnlockList;
                               end;
                               if (QTrader.DdeServer.Handle <> 0) then
                                 PostMessage(QTrader.DdeServer.Handle, WM_DDE_ADDQUE, 0, 0);
                               result:= DDE_FACK;
                             end;
                   paPass: result:=  DDE_FACK;
                   paReject: result:=  DDE_FNOTPROCESSED;
                 end;
               end;
  end;
end;


constructor TDdeServer.Create;
begin
  inherited;
  fDdeQue := TThreadList.Create;
  Parent := TWinControl(AOwner);
  CreateHandle;
  Inst := 0;
  if (DdeInitialize(Inst, @CallbackProc, APPCLASS_STANDARD, 0) = DMLERR_NO_ERROR) then
  begin
    ServiceHSz := DdeCreateStringHandle(Inst, PWideChar( ServiceName ), CP_WINUNICODE);
    if ( DdeNameService(Inst, ServiceHSz, 0, DNS_REGISTER) = 0 ) then
      raise Exception.Create( 'Не удалось зарегистрировать имя DDE-сервиса ''' +
                                                           ServiceName + '''' );
    TopicHSz := DdeCreateStringHandle(Inst, PWideChar('Topic'), cp_WinUnicode);
  end else
    raise Exception.Create( 'Не удалось выполнить инициализацию DDE' );
end;

destructor TDdeServer.Destroy;
begin
  DdeNameService(Inst, ServiceHsz, 0, DNS_UNREGISTER);
  fDdeQue.Free;
  DdeFreeStringHandle(Inst, ServiceHsz);
  DdeUninitialize(Inst);
  inherited;
end;

procedure TDdeServer.AddQue(var Message: TWMSysCommand);
var
  vt: TVariantTable;
  Cells: TRect;
  p: PDdeQueItem;
  i: integer;
begin
  with fDdeQue.LockList do
  try
    p:= PDdeQueItem(Items[Count - 1]);
    Cells:= DecodeCellAddr(p^.sCells);
    vt:= XLTDecodeV(p^.data, p^.size);
    if Assigned(QTrader.DdeServer.fOnData) then
      QTrader.DdeServer.fOnData(p^.sTopic, Cells, vt);
    for i:= (Count - 1) downto 0 do
    begin
      p:= Items[i];
      FreeMem(p^.data, p^.size);
      Delete(i);
      Dispose(p);
    end;
  finally
    fDdeQue.UnlockList;
  end;
end;


function TDdeServer.XLTDecodeV(data: pointer; datasize: integer): TVariantTable;
var
  i: integer;
  curr: pointer;
  BlockType: word;
  BlockSize: word;
  StringSize: byte;
  RealData: real;
  StringData: shortstring;
  DataNum: integer;
begin
  curr:= addp(data, 4);
  result.RowCount := Word(curr^);
  curr:= addp(curr, 2);
  result.ColCount := Word(curr^);
  curr:= addp(curr, 2);
//--- set array size ---
  SetLength(result.Cells, result.RowCount);
//---
  for i := 0 to result.RowCount - 1 do
    SetLength(result.Cells[i], result.ColCount);
//--- data block --------
  DataNum := 0;
  while (Integer(subp(curr, data)) < datasize) do
  begin
    BlockType:= Word(curr^);
    curr:= addp(curr, 2);
    BlockSize:= Word( curr^ );
    curr:= addp( curr, 2 );
    case BlockType of
      1: begin
           while(BlockSize > 0) do
           begin
             RealData:= Real(curr^);
             curr:= addp(curr, 8);
             dec(BlockSize, 8);
             result.Cells[(DataNum div result.ColCount),
                          (Datanum mod result.ColCount)]:= RealData;
             inc(DataNum);
           end;
         end;
      2: begin
           while(BlockSize > 0) do
           begin
             StringSize:= Byte(curr^);
             curr:= addp( curr );
             StringData[0]:= AnsiChar(Chr(StringSize));
//---
             for i:= 1 to StringSize do
             begin
               StringData[i]:= AnsiChar(Char(curr^));
               curr:= addp(curr);
             end;
             result.Cells[(DataNum div result.ColCount),
                          (Datanum mod result.ColCount)]:= StringData;
             inc(DataNum);
             dec(BlockSize, StringSize + 1);
           end;
         end;
    end;
  end;
end;


function TDdeServer.DecodeCellAddr( CellAddr: string ): TRect;
var
  tmp1, tmp2: integer;
begin
  CellAddr:= UpperCase(CellAddr);
  tmp1:= PosEx('R', CellAddr);
  tmp2:= PosEx('C', CellAddr, tmp1);
  try
    result.Top:= StrToInt(copy(CellAddr, tmp1 + 1, tmp2 - tmp1 - 1)) - 1;
  except
    exit;
  end;
  tmp1:= PosEx('R', CellAddr, tmp2);
  try
    Result.Left:= StrToInt(copy(CellAddr, tmp2 + 1, tmp1 - tmp2 - 1 - 1)) - 1;
  except
    exit;
  end;
  tmp2:= PosEx('C', CellAddr, tmp1);
  try
    result.Bottom:= StrToInt(copy(CellAddr, tmp1 + 1, tmp2 - tmp1 - 1)) - 1;
    result.Right:= StrToInt(copy(CellAddr, tmp2 + 1, Length(CellAddr) - tmp2)) - 1;
  except
    exit;
  end;
end;

procedure ClearTable(Table: TVariantTable);
begin
  SetLength(Table.Cells, 0);
  Table.RowCount:= 0;
  Table.ColCount:= 0;
end;


function addp(P: Pointer; increment: int64 = 1): Pointer; overload;
begin
  result:= Pointer(Int64(p) + increment);
end;

function addp(P: Pointer; increment: Pointer): Pointer; overload;
begin
  result:= Pointer(Int64(p) + Int64(increment));
end;

function subp(P: Pointer; decrement: int64 = 1): Pointer; overload;
begin
  result:= Pointer(Int64(p) - decrement);
end;

function subp(P: Pointer; decrement: Pointer): Pointer; overload;
begin
  result:= Pointer(Int64(p) - Int64(decrement));
end;

end.
 
prostotrader:

Alexey VolchanskiyStanislav Dray

Вы все-равно будете писать СВОЁ приложение, человеку не нужно связывать МТ5 с КВИК.

Поэтому самый лучший вариант, это как я описал выше.

Пишем DDE сервер, туда же "цепляем" trans2quik.dll и робот(ы) готов.

круть, лет 15 Дельфю не щупал ))

 
Alexey Volchanskiy:

круть, лет 15 Дельфю не щупал ))

Леш, да какая разница на чем писать?

Просто XE4 у меня лицензионная и 64-битная.

Досталась по случаю.