Gelium Puls.

История изменений:

02.10.2013  Добавлено описание функции GetTick.
12.09.2013  Выложена инсталляция Puls 2013.322. Список изменений.
12.09.2013  Выложена инсталляция Puls 2013.319. Список изменений.



Оглавление:

Установка.
Описание библиотеки.
Список объявлений функций.
Функции для работы с сериями данных.
Функции для работы с файлами.
Функции для работы с диалоговыми окнами.
Сервисные функции.
Функция GetTick для работа с тиковой базой.
Вопросы и ответы.



Установка.

Для получения возможности использования функций библиотеки, необходимо скачать и установить дистрибутив Puls. Затем можно проимпортировать готовый набор промежуточных функций из файла Puls.els с помощью TradeStation Development Environment или EasyLanguage PowerEditor (главное меню File / Import and Export). Ярлык на файл Puls.els создается в группе программ Puls.

Скачать последнюю версию:
Изменения в Puls 2013.322:
  • Мелкие улучшения в работе интерфейса главного окна Puls.
  • Оптимизирована работа функции GetTick.
Изменения в Puls 2013.319:
  • В стандартную версию Puls.DLL (32 bit) добавлена функция GetTick для тестирования торговых стратегий по точным ценам на базе тиков. Работу с тиками поддерживает стратегия Gelium_Trader.
Скачать предыдущую стабильную версию: Изменения в Puls 2013.281:
  • Добавлено сохранение ширины столбцов в списках с данными.
  • Добавлен флажок для включения/отключения скрытия окна комментариев эксперта TradeStation.
  • Добавлена функция вызова окна ввода значения с именем InputM для совместимости с MultiCharts. Функция полностью идентична функции Input:
    "DefineDLLfunc:"puls.dll",BOOL, "INPUTM",LPSTR, LPFloat;"
  • Окно со списком команд автоматически позиционируется относительно указателя мыши в момент вызова. Ширину окна можно менять по своему желанию.
  • Добавлена функция SeriesGet15 для получения 15 значений по третьему индексу одного элемента серии.
  • Добавлена функция SeriesGetList для получения всех значений по третьему индексу одного элемента серии.
  • Убрано ограничение на сохранение и отображение только 4 десятичных знаков для элементов серии, хранящейся в фале.

Описание библиотеки.

Библиотека Puls предназначена для расширения функций таких программ технического анализа как TradeStation, ProSuite 2000i и так далее. Библиотека выполнена в виде подключаемого модуля DLL, который позволяет реализовать работу с глобальными массивами числовых и текстовых переменных; работу с файлами; диалоговые функции для организации интерактивного взаимодействия с пользователем.

Библиотека Puls.

Обратите внимание:
  • С расширением возможностей языка EasyLanguage, поддерживаемого TradeStation 9.1, необходимость в Puls частично отпала. Работу с файлами обеспечивает класс из библиотеки elsystem.io, глобальную коллекцию данных можно организовать с помощью GlobalDictionary, создание пользовательских форм любой сложности обеспечивают классы из библиотеки winforms. Если вы планируете делать собственные разработки на базе TradeStation 9.1, дополнительная библиотека может не понадобится.

  • С MultiCharts можно использовать Puls, но после выгрузки библиотеки из памяти MultiCharts 8.x зависает. Причина и методы ее решения пока не известны. Поэтому для более-менее нормально работы в MultiCharts должно быть открыто несколько окон с индикаторами/стратегиями, использующими Puls. Чтобы во время работы MultiCharts не выгружал библиотеку из памяти и не зависал из-за этого.

Список объявлений функций.

DefineDLLfunc:"puls.dll",	BOOL,	"SERIESSAVE",    LPSTR, BOOL;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESSET",	 LPSTR, INT, INT, Float;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESSETSTR",  LPSTR, INT, INT, LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESGETDTV",	 LPSTR, INT, INT, BOOL, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESGET",	 LPSTR, INT, INT, BOOL, LPFloat;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESGET15",	 LPSTR, INT, INT, BOOL, INT, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat;
DefineDLLfunc:"puls.dll",	LPSTR,	"SERIESGETLIST", LPSTR, INT, INT, BOOL;
DefineDLLfunc:"puls.dll",	LPSTR,	"SERIESGETSTR",  LPSTR, INT, INT, BOOL;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESDELETE",  LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESCLEAR",   LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"SERIESREMOVE",  LPSTR, INT, INT;
DefineDLLfunc:"puls.dll",	BOOL,	"FILEOPENFORWRITE", 	LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"FILEOPENFORREAD",  	LPSTR;
DefineDLLfunc:"puls.dll",	LPSTR, 	"FILEREAD",		LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"FILEWRITE", 		LPSTR, LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"FILECLOSE", 		LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"SHOWLISTW",	 LPSTR, LPSTR, LPSTR;
DefineDLLfunc:"puls.dll",	LPSTR,	"SHOWLIST",	 LPSTR, LPSTR;
DefineDLLfunc:"puls.dll",	INT,	"SHOWDIALOG",	 LPSTR, LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"INPUT",	 LPSTR, LPFloat;
DefineDLLfunc:"puls.dll",	BOOL,	"INPUTM",	 LPSTR, LPFloat;
DefineDLLfunc:"puls.dll",	BOOL,	"LOG", LPSTR;
DefineDLLfunc:"puls.dll",	BOOL,	"LOGCLEAR";
DefineDLLfunc:"puls.dll",	BOOL,	"HIDECOMMENT";
DefineDLLfunc:"pulshc.dll",	LPSTR,	"GETKEYSTATE";

Функции для работы с сериями данных.


Серия - это трехмерный массив данных неограниченного размера, числовые и текстовые данные которого могут храниться в файлах. Все данные серии загружаются в оперативную память для обеспечения максимальной скорости выборки.

Пример установки данных элемента серии:
b = gp_SeriesSet("MySeries", Date, Time, Value1);
b = gp_SeriesSet("MySeries+1", Date, Time, Value2);
Где Date, Time - первые два индекса элемента серии, +1 - третий индекс элемента серии.
Функция gp_SeriesSave устанавливает или снимает флаг хранения данных серии в файле.

Первый параметр функции - строка с именем серии.
Второй параметр функции - флаг хранения данных в файле.

В качестве результата функция всегда возвращает true.
b = gp_SeriesSave("MySeries", true);

Функция gp_SeriesClear удаляет все данные серии.

Первый параметр функции - строка с именем серии.

В качестве результата функция всегда возвращает true.
b = gp_SeriesClear("MySeries");

Функция gp_SeriesSet устанавливает числовое значение элемента серии.

Первый параметр функции - строка с именем серии.
Второй параметр - первый индекс массива (как правило дата).
Третий параметр - второй индекс массива (как правило время).
Четвертый параметр - числовое значение элемента серии.

В качестве результата функция всегда возвращает true.
b = gp_SeriesSet("MySeries", Date, Time, Value1);
b = gp_SeriesSet("MySeries+1", Date, Time, Value2);

Функция gp_SeriesSetStr устанавливает текстовое значение элемента серии.

Первый параметр функции - строка с именем серии.
Второй параметр - первый индекс массива (как правило дата).
Третий параметр - второй индекс массива (как правило время).
Четвертый параметр - текстовое значение элемента серии.

В качестве результата функция всегда возвращает true.

b = gp_SeriesSetStr("MySeries", Date, Time, "Value1 =" + NumToStr(Value1, 4));

Обратите внимание на то, что элемент серии может хранить только одно текстовое значение. Недопустимо указание рядом с именем серии третьего индекса. Такой вызов функции будет не правильным:
b = gp_SeriesSetStr("MySeries+1", Date, Time, "Value2 =" + NumToStr(Value2, 4));

Функция gp_SeriesGet возвращает числовое значение элемента серии.

Первый параметр функции - строка с именем серии.
Второй параметр - первый индекс массива (как правило дата).
Третий параметр - второй индекс массива (как правило время).
Четвертый параметр - флаг допустимости получения, в качестве значения элемента серии, значение элемента с меньшим индексом, если элемент серии с запрашиваемым индексом отсутствует.
Пятый параметр - переменная, в которую необходимо вернуть числовое значение элемента серии.

В качестве результата функция возвращает true, если удалось получить значение элемента серии и false, если элемент серии не был найден.

Например, в серии есть следующие данные:

[1, 1] Значение 100.
[2, 2] Значение 200.
[4, 4] Значение 400.
b = gp_SeriesGet("MySeries", 1, 1, false, MyValue); 
Функция вернет true, MyValue = 100.
b = gp_SeriesGet("MySeries", 3, 3, false, MyValue); 
Функция вернет false, MyValue = 0.
b = gp_SeriesGet("MySeries", 3, 3, true, MyValue); 
Функция вернет true, MyValue = 200.

Функция gp_SeriesGetDTV возвращает числовое значение элемента серии и значения индексов элемента серии.

Пример вызова:
if gp_SeriesGetDTV(SeriesName, GetIndex1, GetIndex2, true, ResultIndex1, ResultIndex2, 
MyValue, NextIndex1, NextIndex2) then
Параметр Назначение
SeriesName Название серии данных.
GetIndex1 Первый индекс требуемого элемента серии (как правило, дата).
GetIndex2 Второй индекс требуемого элемента серии (как правило, время).
True / False Флаг допустимости использования элемента серии с меньшим индексом, если элемент серии с запрашиваемым индексом отсутствует.
ResultIndex1 Переменная, в которую необходимо вернуть значение первого индекса найденного элемента серии.
ResultIndex2 Переменная, в которую необходимо вернуть значение второго индекса найденного элемента серии.
MyValue Переменная, в которую будет возвращено числовое значение найденного элемента серии.
NextIndex1 Переменная, в которую будет возвращено значение первого индекса следующего элемента серии, если следующий элемент есть в наличии. Если следующий элемент отсутствует, будет возвращено значение -1.
NextIndex2 Переменная, в которую будет возвращено значение второго индекса следующего элемента серии, если следующий элемент есть в наличии. Если следующий элемент отсутствует, будет возвращено значение -1.

В качестве результата функция возвращает true, если удалось получить значение элемента серии и false, если элемент серии не был найден.

Информация об индексах следующего элемента серии может использоваться для того, чтобы осуществлять запрос данных серии не на каждом баре, а по достижению нужного бара. Такой подход экономит время и сокращает число вызовов.

Например, в серии есть следующие данные:

[1, 1] Значение 100.
[2, 2] Значение 200.
[4, 4] Значение 400.
b =gp_SeriesGetDTV("MySeries", 1, 1, false, Index1, Index2, MyValue, NextIndex1, NextIndex2);
Функция вернет true, MyValue = 100, Index1 = 1, Index2 = 1.
b =gp_SeriesGetDTV("MySeries", 3, 3, false, Index1, Index2, MyValue, NextIndex1, NextIndex2);
Функция вернет false, MyValue = 0,  Index1 = 0, Index2 = 0.
b =gp_SeriesGetDTV("MySeries", 3, 3, true, Index1, Index2, MyValue, NextIndex1, NextIndex2);
Функция вернет true, MyValue = 200, Index1 = 2, Index2 = 2.

Функция gp_SeriesGetStr возвращает текстовое значение элемента серии.

Первый параметр функции - строка с именем серии.
Второй параметр - первый индекс массива (как правило дата).
Третий параметр - второй индекс массива (как правило время).
Четвертый параметр - флаг допустимости получения, в качестве значения элемента серии, значение элемента с меньшим индексом, если элемент серии с запрашиваемым индексом отсутствует.

В качестве результата функция возвращает текстовое значение элемента серии. Если элемент отсутствует, возвращается пустая строка.
Txt = gp_SeriesGetStr("MySeries", 1, 1, false);
Обратите внимание на то, что элемент серии может хранить только одно текстовое значение. Недопустимо указание рядом с именем серии третьего индекса. Такой вызов функции будет не правильным:
Txt = gp_SeriesGetStr("MySeries+1", 1, 1, false);

Функция gp_SeriesRemove удаляет элемент серии.

Первый параметр функции - строка с именем серии.
Второй параметр - первый индекс массива (как правило дата).
Третий параметр - второй индекс массива (как правило время).

В качестве результата функция всегда возвращает true.
b = gp_SeriesRemove("MySeries", Date, Time);

Функция SeriesGet15 возвращает 15 значений элемента серии.

Объявление функции:
DefineDLLfunc:"puls.dll", BOOL, "SERIESGET15", LPSTR, INT, INT, BOOL, INT, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat, LPFloat;

Параметры функции:
  • Первый параметр функции - строка с именем серии.
  • Второй параметр - первый индекс массива (как правило дата).
  • Третий параметр - второй индекс массива (как правило время).
  • Четвертый параметр - флаг допустимости получения, в качестве значения элемента серии, значение элемента с меньшим индексом, если элемент серии с запрашиваемым индексом отсутствует.
  • Пятый параметр - смещение третьего индекса элемента серии относительно нулевого значения третьего индекса.
  • С шестого по 21 параметры - переменные, в которые будут возвращены данные элемента серии.
В качестве результата функция возвращает true, если удалось получить значение элемента серии и false, если элемент серии не был найден.

В примере далее запрашиваются 15 значений элемента серии, начиная со значения третьего индекса 3. То есть, пропускаются элементы "Series", "Series+1", "Series+2" и запрашиваются элемеенты ["Series+3".."Series+27"]:
If SeriesGet15(wp_SeriesName, date, time, true, 3, 
	&bs1_Price, &bs2_Date, &bs2_Time, &bs2_Price, &bf1_Date, &bf1_Time, &bf1_Price,	
	&Value1, &Value1, &Value1, 
	&b_ModelStatus, &Value1, &Value1, &Value1, &Value1) then begin

Функция SeriesGetList возвращает все значения элемента серии по третьему индексу.

Объявление функции:
DefineDLLfunc:"puls.dll",	LPSTR,	"SERIESGETLIST", LPSTR, INT, INT, BOOL;

Параметры функции:
  • Первый параметр функции - строка с именем серии.
  • Второй параметр - первый индекс массива (как правило дата).
  • Третий параметр - второй индекс массива (как правило время).
  • Четвертый параметр - флаг допустимости получения, в качестве значения элемента серии, значение элемента с меньшим индексом, если элемент серии с запрашиваемым индексом отсутствует.
В качестве результата функция возвращает текст со всеми значениями элемента серии. Если получить значение элемента серии не удалось, возвращается пустая строка.

Пример вызова функции:
txt = SeriesGetList(wp_SeriesName, date, time, true);

Функции для работы с файлами.


Функция gp_FileOpenForWrite открывает файл для записи.

Если файл с таким именем уже существует, то данные в него дописываются. Один и тот же файл может быть открыт только для чтения или только для записи. После завершения работы с файлом, файл надо закрыть вызовом функции gp_FileClose.

Первый параметр функции - строка с именем файла.

Если операция открытия файла успешна, функция возвращает true. В противном случае функция возвращает false.
if gp_FileOpenForWrite("c:\PulsDemo1.txt") then begin
  b = gp_FileWrite("c:\PulsDemo1.txt", "Hello!");
  b = gp_FileClose("c:\PulsDemo1.txt");
end;

Функция gp_FileOpenForRead открывает файл для чтения.

Один и тот же файл может быть открыт только для чтения или только для записи. После завершения работы с файлом, файл надо закрыть вызовом функции gp_FileClose.

Первый параметр функции - строка с именем файла.

Если операция открытия файла успешна, функция возвращает true. В противном случае функция возвращает false.

if gp_FileOpenForRead("c:\PulsDemo1.txt") then begin
  txt = "";
  While txt <> "#EOF#" begin
    txt = gp_FileRead("c:\PulsDemo1.txt");
    print("FileRead: ", txt);
  end;
  b = gp_FileClose("c:\PulsDemo1.txt")
end;

Функция gp_FileRead предназначена для чтения текстовой строки из файла.

Первый параметр функции - строка с именем файла.

В качестве результата функция возвращает текстовую строку, которая была прочитана из файла.
Когда достигается конец файла и больше нет данных для считывания, функция возвращает текстовую строку "#EOF# ".
if gp_FileOpenForRead("c:\PulsDemo1.txt") then begin
  txt = "";
  While txt  "#EOF#" begin
    txt = gp_FileRead("c:\PulsDemo1.txt");
    print("FileRead: ", txt);
  end;
  b = gp_FileClose("c:\PulsDemo1.txt");
end;

Функция gp_FileWrite предназначена для записи данных в файл.

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

Если операция записи данных в файл успешна, функция возвращает true. В противном случае функция возвращает false.
if gp_FileOpen("c:\PulsDemo1.txt") then begin
  b = gp_FileWrite("c:\PulsDemo1.txt", NumToStr(Date, 0) + "," + 
      NumToStr(Time, 0) + "," + NumToStr(c, 4));
  b = gp_FileClose("c:\PulsDemo1.txt");
end;

Функция gp_FileClose предназначена для закрытия открытого ранее файла.

Первый параметр функции - строка с именем файла.

В случае успешности закрытия файла, функция возвращает true. В противном случае функция возвращает false.
if gp_FileOpen("c:\PulsDemo1.txt") then begin
  b = gp_FileWrite("c:\PulsDemo1.txt", NumToStr(Date, 0) + "," + 
      NumToStr(Time, 0) + "," + NumToStr(c, 4));
  b = gp_FileClose("c:\PulsDemo1.txt");
end;

Функции для работы с диалоговыми окнами.


Функция gp_Input выводит диалоговое окно с запросом значения числовой переменной.


Если пользователь в диалоговом окне нажимает Ok, функция возвращает true. Если пользователь закрывает окно или нажимает Отмена, функция возвращает false.

Введенное значение возвращается в переменную, которая использовалась в параметрах функции.
if gp_ShowDialog("Хотите изменить значение переменной?", "Да,Нет") = 1 then begin
{Запрашиваем значение переменной}
if gp_Input("Введите значение переменной", p) then
print("Input: ", p);
end;

Функция gp_ShowList выводит диалоговое окно с заданным текстом и списком выбора.
print("List: ", gp_ShowList("Выберите необходимое действие:", "Buy=Купить | Sell=Продать |-| Exit=Закрыть позиции"));

Первый параметр функции - текст сообщения, который выводится в верхней части окна. Второй параметр функции - перечисление списка вариантов выбора. Вариант выбора состоит из имени и выводимого текста. Например, Buy=Купить означает, что вариант Buy в списке будет представлен текстом Купить.

Варианты разделяются символом |. Выбор варианта пользователь осуществляет нажатием клавиши Enter или двойным кликом по нужной строке. Закрытие окна или нажатие клавиши ESC эквивалентно отказу от выбора варианта.

Возвращаемое функцией значение - имя выбранного варианта и текст =1. Например, если пользователь выберет в приведенном выше примере строку Купить, то функция вернет текст Buy=1.

Функция gp_ShowDialog выводит диалоговое окно с заданным текстом и набором кнопок, которые может нажать пользователь.

Названия кнопок перечисляются через запятую.


Возвращаемое значение - номер нажатой кнопки. Если пользователь закрывает окно без нажатия какой-либо кнопки, функция возвращает ноль.

if gp_ShowDialog("Хотите изменить значение переменной?", "Да,Нет") = 1 then begin
{Запрашиваем значение переменной}
if gp_Input("Введите значение переменной", p) then
print("Input: ", p);
end;

Сервисные функции.


Функция gp_LogClear очищает поле протокола в окне Puls.

Возвращаемое значение всегда true.
Vars: b(false);
b = gp_LogClear;

Функция gp_Log выводит текстовое значение в протокол Puls.

Возвращаемое значение всегда true.
Vars: b(false);
b = gp_Log("Hello Puls!");

Функция GetTick.

Функция GetTick позволяет получить значение первого тика, который будет соответствовать заданным ценовым и временным параметрам. Точное значение первого тика необходимо для того, чтобы в стратегии установить ордер по заданной цене тика. Если стратегия будет работать на базе минутных баров без тиковой истории, ценовые разрывы внутри этих баров не будут учтены. В итоге не будут учтены дополнительные издержки, которые создают проскальзывания.

Более подробно тема тестирования стратегий и учета проскальзываний рассматривается в статьях "На каком периоде лучше просчитывать исполнение ордеров внутри бара" и "Золотая волатильность". Без самостоятельного программирования работу с тиковыми базами можно осуществлять с помощью МТС Gelium_Trader (версия для TradeStation).

Для работы функции GetTick необходимы тиковые базы в формате T_Puls. Готовые базы данных можно скачать отсюда. Архивы с тиковыми базами надо распаковать в один каталог. Например, "C:\History\Tick". В главном окне Puls, во вкладке "Параметры", необходимо указать путь к каталогу с тиковыми базами:

Библиотека Puls.

Рассмотрим объявление и вызов функции GetTick:

DefineDLLfunc:"puls.dll", BOOL, "GETTICK", LPSTR, INT, INT, INT, LPInt, LPFloat, LPInt;
...

OrderSellBid = OrderSell; OS_Bid = OrderSell; OS_RID = 0; If c >= OrderSell then Value1 = -1 Else Value1 = 1; if GetTick(p_TickBaseFile, Value1, BarDTime1, BarDTime2, &OS_DTime, &OS_BID, &OS_RID) then OrderSellBid = OS_Bid;

Параметр p_TickBaseFile указывает функции GetTick, из какой именно тиковой базы данных необходимо получить информацию. Например, в качестве базы можно указать "XAU-FUT". Путь и расширение файла указывать не надо.

Если переменная Value1 = 1, значение первого тика должно быть равным или большим исходной цены ордера, которую хранит переменная OS_BID. В противном случае значение первого тика должно быть меньше или равно исходной цены ордера, которую хранит переменная OS_BID.

Переменные BarDTime1 и BarDTime2 указывают, в каком временном диапазоне должны находиться тики. Тики должны иметь время > BarDTime1 и <= BarDTime2. Это позволяет использовать в качестве диапазона время закрытия текущего бара и следующего бара, для которого и определяется значение цены тика.

Переменная OS_DTime ничего не передает функции и в качестве возврата получает время найденного тика, если тик будет найден.

На входе переменная OS_RID передает функции номер записи, после которой должен располагаться тик в базе данных. Все тики в базе данных имеют уникальный номер и следуют друг за другом в порядке возрастания времени. Первый тик имеет номер 1, следующий 2 и так далее. Если мы определили, что номер тика для открытия короткой позиции равен 100, то тики для установки стопа или лимита для этой позиции должны иметь номер больше 100, так как стоп или лимит могут сработать только после открытия короткой позиции. Поскольку в примере выше запрашивается цена тика для открытия позиции, OS_RID = 0. Если подходящий тик будет найден, его номер будет возвращен в переменную OS_RID.

Если подходящий тик находится в базе данных, функция возвращает true и передает данные в переменные OS_DTime, OS_BID и OS_RID. Если тик не найден, функция возвращает false, исходное значение ордера не меняется и цена исполнения ордера будет зависить от торговой платформы.

Если делать запросы для ордеров, параметры которых лежат вне пределов следующего бара, будет теряться время на бессмысленных запросах. Ведь нет смысла запрашивать цену тика, которого в базе точно нет. Для такой проверке придется загрузить тики из базы в память, проверить их все и вернуть false. Такие бессмысленные запросы способны значительно затормозить оптимизацию стратегий. Поэтому я сохраняю значения H, L баров в серию данных и перед запросом точной цены тика проверяю в коде стратегии, попадает ли цена ордера внутрь следующего бара. На принятие торговых решений такая проверка никакого влияние не оказывает, зато позволяет делать только нужные запросы к базе данных. Таким образом, один раз стратегия сохраняет данные баров в серию и не производит получение данных из базы. В дальнейшем параметры баров берутся из серии и осуществляется точная установка ордеров согласно тикам из базы.

Рассмотрим пошагово использование тиковой базы для точной установки ордеров:

// Объявление функции
DefineDLLfunc:"puls.dll", BOOL, "GETTICK", LPSTR, INT, INT, INT, LPInt, LPFloat, LPInt;

Объявляем необходимые переменные:

Vars:

...
// Тиковая оптимизация wp_TickBase(false), SeriesHL(""), NextBarH(0), NextBarL(0), BarDTime1(0), BarDTime2(0),
// OredrBuy OB_Bid(0), OB_Rid(0), OB_DTime(0),
// OredrSell OS_Bid(0), OS_Rid(0), OS_DTime(0),
// OredrSell Stop SS_Bid(0), SS_Rid(0), SS_DTime(0),
// OredrBuy Stop BS_Bid(0), BS_Rid(0), BS_DTime(0),
// OredrSell Limit SL_Bid(0), SL_Rid(0), SL_DTime(0),
// OredrBuy Limit BL_Bid(0), BL_Rid(0), BL_DTime(0),

Включаем запись в файл серии данных один раз на первом баре:

If p_TickBase > 0 then begin 
	SeriesHL = "XHL_" + mSymbol() + "_" + NumToStr(barinterval, 0);
	SeriesSave(SeriesHL, true);
end;		

Перед вызовами GetTick один раз для каждого бара получаем значения H, L следующего бара. Если данных в серии нет или они отличаются от текущей истории, записываем их в серию:

If p_TickBase > 0 then begin
	BarDTime1 = mDTime(Date, Time);
	BarDTime2 = mDTime(Date Next bar, Time Next bar);
	If Currentbar > 1 then
	if wp_TickBase[1] = false or 
		AbsValue(NextBarH - h) > 1 point or 
		AbsValue(NextBarL - L) > 1 points 
	then begin
		SeriesSet(SeriesHL, Date, Time, H);
		SeriesSet(SeriesHL + "+1", Date, Time, L);
	end;
	NextBarH = 0;
	NextBarL = 0;
	SeriesGet(SeriesHL, Date Next bar, Time Next Bar, false, &NextBarH);
	SeriesGet(SeriesHL + "+1", Date next bar, Time Next Bar, false, &NextBarL);
	wp_TickBase = (NextBarH > 0 and NextBarL > 0); 
end;

Получаем значение тика для ордера покупки:

	If wp_TickBase then
	if OrderBuy <= NextBarH then
	if OrderBuy >= NextBarL then begin
		OB_Bid = OrderBuy;
		OB_RID = 0;
		If c >= OrderBuy then
			Value1 = -1
		Else				
			Value1 = 1;
				
		if GetTick(p_TickBaseFile, Value1, BarDTime1, BarDTime2, &OB_DTime, &OB_Bid, &OB_RID) then 
			OrderBuyBid = OB_Bid;
	end;				
	if OrderBuyBid < c then begin
		Buy ("b") PosSize contracts Next Bar OrderBuyBid limit;
	end else begin
		Buy ("b ") PosSize contracts Next Bar OrderBuyBid stop;

Получаем значение тика для stop-ордера длинной позиции:

	If wp_TickBase then
	if PosBuyStop <= NextBarH then 
	if PosBuyStop >= NextBarL then begin
		BS_Bid = PosBuyStop;
		BS_RID = OB_RID;
		Value1 = -1;
		if GetTick(p_TickBaseFile, Value1, BarDTime1, BarDTime2, &BS_DTime, &BS_BID, &BS_RID) then 
			PosBuyStop = BS_Bid;
	end;				
	Sell ("Ls+ ") Next Bar PosBuyStop stop;

Получаем значение тика для limit-ордера длинной позиции:

	If wp_TickBase then
	if PosBuyLimit <= NextBarH then 
	if PosBuyLimit >= NextBarL then begin
		BL_Bid = PosBuyLimit;
		BL_RID = OB_RID;
		Value1 = 1;
		if GetTick(p_TickBaseFile, Value1, BarDTime1, BarDTime2, &BL_DTime, &BL_BID, &BL_RID) then 
			PosBuyLimit = BL_Bid;
	end;				
	Sell ("Li+") Next Bar PosBuyLimit limit;

В переменную OB_RID возвращается номер записи тика, по которому будет открыта длинная позиция. Тики для стопа и лимита должны быть после тика открытия позиции. Поэтому для стоп и лимит-ордеров, кроме указания временного интервала, передается значение OB_RID через отдельные переменные BS_RID и BL_RID. Отдельные переменные нужны для того, чтобы возвращая значение номера записи найденного тика, не было затерто исходное значение переменной OB_RID.

В главном окне Puls, для отладки и работы с тиковыми базами, есть отдельная вкладка Tick:

Библиотека Puls.

Сверху располагается панель с полями ввода, кнопками "Запрос" и "Сервис", полем для вывода информации о времязатратах и числе выполненных запросов. На рисунке выше ко всем базам данных было выполнено 11979 запросов. Для их выполнения потребовалось 4 секунды 778 миллисекунд.

Под панелью с полями и кнопками располагается список запросов к базам данных. Этот список автоматически обновляется только в режиме отладки, так как на обновление этой информации тратится время. Для включения/отключения режима отладки, необходимо нажать кнопку "Сервис" и выбрать в выпадающем меню пункт "Отладка". Поскольку в режиме отладки тратится достаточно много времени на вывод протокола и сохранение списка запросов, пользоваться им желательно только во время отладки кода стратегии. Во время оптимизации стратегии этот режим надо отключать.

Под списком запросов располагается список тиков, которые были извлечены из базы данных для выбранного в списке запроса.

Для выполнения запроса к базе данных надо выбрать нужный вам запрос. Если надо, вручную изменить его параметры через соответствующие поля ввода и нажать кнопку "Запрос". Либо дважды кликнуть по нужному запросу в списке всех запросов. После выполнения запроса обновится список тиков. Строка с найденным тиком будет активирована автоматически.

Вопросы и ответы.

  • Когда выполняются функции, в начале бара или в конце?

    Выполнение кода всегда выполняется в момент закрытия бара. В тех случаях, когда для стратегий указывается срабатывание внутри бара, вызов происходит многократно, но каждый раз это будет вызов с изменением цены Close.

  • Можно ли передавать серии по сети или между разными программами?

    Чтобы сделать данные доступными с другого компьютера или программы, придется использовать текстовый файл.

  • В чарте индикатором сохраняю серию значений. Другим индикатором в RadarScreen-e пытаюсь читать эту серию. Однако библиотека Puls загружается еще раз. Появляется еще одно окно Puls и иконка в трее. В этом новом окне видно, что запрашиваемая серия пустая, данных там нет. Возможно ли это поправить, чтобы обращение к Puls из RadarScreen приводило к вызову уже существующего экземпляра Puls?

    Синхронизации данных между несколькими экземплярами Puls в памяти нет. В TradeStation 9.1 есть специальные классы типа GlobalDictionary, GlobalValue, которые используются для передачи данных между инструментами теханализа внутри платформы.

  • Пробовал свои DLL написать под С++, но ProSuite при обращении к ним виснет "мертво". Может есть фишка какая с ProSuite+DLL? Может в заголовках С++ дополнительно чего писать надо?

    Необходимая для написания DLL информация есть в Developer Kit для ProSuite 2000i (http://download.gelium.net/DevKit.exe) или в справке TradeStation.

  • Для хранения разных переменных лучше использовать одну серию или разные?

    Для логически связанных между собой переменных удобнее использовать одну серию.

  • Минимальный шаг индексов - целое число. А как хранить тики с указанием секунд и микросекунд?

    Просто форматируйте время как целое число. Например, 12:35:01 сохраняйте с индексом 1235010.

  • При открытии окна Puls зависает MultiCharts 7. Что с этим делать?

    Чтобы MultiCharts версий ниже 8.0 не зависал во время вызова главного окна Puls при старте, в puls.ini укажите:

    [Main]
    Tray=0

    После запуска MultiCharts, иконка вызова главного окна Puls в системном трее создаваться не будет.
Прочитано 40575 раз Последнее изменение Вторник, 01 Октябрь 2013 07:24
Другие материалы в этой категории: TradeInterceptor. »



Перепечатка авторских материалов сайта без указания ссылки на
сайт Gelium.net запрещена.

Pavel Gelium 2000-2017 © All rights reserved.