Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пишем библиотеку DLL для Metastock с нуля. Часть 1

Anna | 24.06.2014 | нет комментариев
Metastock – вероятно, самая знаменитая программа для технического обзора рынка. Данная программа может подключать внешние библиотеки DLL, написанные пользователями для создания своих торговых стратегий, применяя полную мощь традиционных языков программирования, таких как C либо Паскаль.
Занявшись поиском в интернете, с изумлением нашел полное неимение информации по данной теме. Исключительная статья, которая оказалась достойной внимания: “Что такое Metastock Developer’s Kit?” (mdk), где описывается коротенький пример на Delphi, там же дозволено скачать MDK.
В данной статье я постараюсь заполнить данный пробел и описать процесс создания библиотеки внешних функций Metastock (MSX DLL) по шагам на языке C/C . Все примеры писались в среде Visual Studio 2010.

Немножко теории

Функции, которые реализованы в MSX DLL ведут себя верно также как и типовые встроенные функции Metastock’а. Все функции MSX DLL возвращают массив данных. Всякая внешняя функция имеет неповторимое имя.

ExtFml(«DLL Name.Function Name»,arg1,…,argn), где

arg1…argn – доводы функции (n <= 9).

Всякий довод может быть одним из четырех типов:
• Массивы данных (скажем, Open, High, Low, Close, и т.д., либо итоги иной функции)
• Числовые константы (скажем, 5, -5, 20.55 и т.д.)
• Строковые константы (скажем, “Hello Woodpecker” и др.)
• Индивидуальные комплекты (скажем, Simple, Triangular, и т.д.)
Как их определять и применять мы разглядим позднее, на определенных примерах.

Функции, определенные в MSX DLL делятся на две категории:
• Функции инициализации
• Функции расчета (либо внешние функции).
Функции инициализации вызываются MetaStock’ом во время запуска, Дабы определить, какие внешние функции доступны и какие доводы они требуют. Функции расчета доступны для пользователей MetaStock’а. Все функции ссылаются на конструкции данных определенных в файле MSXStruc.h. Данный файл нужен для компиляции нашей DLL.
Раньше чем писать свои функции нужно прописать несколько служебных MSX-функций (функции инициализации), для того что бы Mетосток мог общаться с вашей DLL. Их четыре:
• MSXInfo — непременная функция. Неизменно вызывается во время инициализации и проверяет, является ли наша DLL MSX DLL и возвращает основную информацию о ней (авторство, число наших функций, версия).
• MSXNthFunction — непременная функция. Вызывается один раз для всякой функции указанной MSXInfo и нумерует, начиная с нуля наши функции. Тут прописываются имена функций (c учетом регистра), их дескриптор и число доводов у всякой.
• MSXNthArg – эта функция непременна, только если у наших функций есть доводы. Вызывается во время инициализации для всякого довода наших функций.
• MSXNthCustomString – эта функция непременна, только если у наших функций есть custom-доводы.

Для начала теории довольно, приступим к написанию первой DLL. В этом примере будет показано, как вывести массив цен, дату и время в наш индикатор.

Пишем код

Открываем VS 2010. Первым делом сотворим пустой план.
File->New->Project->Other Languages->Visual C ->Win32->Win32 Console Application.
Задаем имя нашей библиотеки (пускай UsePrice) и нажимаем OK.Открывается Win32 Application Wizard.
Next-> и ставим галочки на DLL и Empty project, нажимаем Finish. Пустой план сделан. Добавим в него три файла UsePrice.cpp, UsePrice.def, MSXStruc.h. Правой кнопкой по плану Add->New Item…, выбираем файл с соответствующим растяжением и задаем ему соответствующее имя. Нажимаем Add.
В файле UsePrice.cpp пишем наш код.

/*
— Шаг 1 – Заголовки

Коментарии

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

*/

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <tchar.h>

// Непременно включить - определяет MSX Data Structures (см. файл MSXStruc.h).

#include "MSXStruc.h"

/*
— Шаг 2 – Экспорт

Коментарии

Директива #define определяет идентификатор и последовательность символов,
которой будет замещаться данный идентификатор при его выявлении в тексте
программы. Идентификатор также именуется именем макроса, а процесс
замещения именуется подстановкой макроса. Типовой вид директивы
дальнейший:#define имя_макроса последовательность_символов

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

Скажем, если нужно применять TRUE для значения 1, a FALSE для 0,
то дозволено объявить следующие два макроса:

#define TRUE 1
#define FALSE 0

В итоге, если компилятор найдет в тексте программы TRUE либо FALSE, то
он заменит их на 1 и 0 соответственно.
В нашем случае если в коде встречается DLL_EXPORT, то выполняется макрос

extern «C» __declspec(dllexport)

Дабы типично спрягать код на C с C, где name mangling отсутствует, введено
extern «C», которое отключает данный механизм у экспортируемых имен переменных/функций.
extern «C» обозначает применение примитивный генерации сигнатуры функции
(в жанре языка С) при приобретении объектных файлов. В частности, это воспрещает
компилятору C изготавливать «декорацию» имени функции дополнительными
символами при экспорте в DLL.
Признак класса хранения dllexport — это специфическое для Microsoft растяжение
языков C и C . Его дозволено применять для экспорта функций, данных и объектов
в библиотеку DLL.
__declspec( dllexport ) declarator
Данный признак очевидно определяют интерфейс DLL для ее заказчика, тот, что может быть
исполняемым файлом либо иной библиотекой DLL. Объявление функций как
dllexport разрешает обходиться без файла определения модуля (DEF), по крайней
мере, в отношении спецификации экспортированных функций.

*/

#define DLL_EXPORT extern "C" __declspec(dllexport)

/*
— Шаг 3 – Функции инициализации

Коментарии

Раньше чем писать свои функции нужно прописать несколько служебных
MSX-функций, для того, Дабы Mетосток мог общаться с нашей DLL.
В первом примере мы будем писать одну функцию без доводов, следственно
MSXNthArg и MSXNthCustomString нам не потребуются.MSXInfo
Замените поле <VS 2010 C MSX DLL, Copyright © Pretzel, 2014> вашей
информацией об авторстве, а также установите число функций = 1.
strncpy (strDest,strSource,count) — копирует символы одной строки в иную.
• strDest — строка назначения.
• strSource — иссходная строка.
• count — число символов для копирования.
strncpy требует непременный заголовок <string.h>.
На strncpy компилятор VS C выдает предупреждения, дозволено применять
strncpy_s (проверял — все работает, но не могу сказать насколько это правильно).

*/

DLL_EXPORT BOOL __stdcall MSXInfo (MSXDLLDef *a_psDLLDef)
{
    strncpy (a_psDLLDef->szCopyright, "VS 2010 C   MSX DLL, Copyright (c) Pretzel, 2014", sizeof(a_psDLLDef->szCopyright)-1);
    a_psDLLDef->iNFuncs = 1;  // число функций.
    a_psDLLDef->iVersion = MSX_VERSION; // версия
    return MSX_SUCCESS;
}

/*

Коментарии

MSXNthFunction
Значение, копируемое в a_sFuncDef->szFunctionName должно верно соответствовать
нашей функции, которую мы будете экспортировать, с учетом регистра.
Изменяемые значения:
• Name — имя нашей функции.
• Description — то, как она будет читаться в Metastock’е (в окне ‘Paste Functions’).
• Arguments — число доводов нашей функции.
На strcpy компилятор VS C выдает предупреждения, дозволено применять strcpy_s
(проверял — все работает, но не могу сказать насколько это правильно).

*/

DLL_EXPORT BOOL __stdcall MSXNthFunction (int a_iNthFunc, MSXFuncDef *a_psFuncDef)
{
   BOOL l_bRtrn = MSX_SUCCESS;

	switch (a_iNthFunc)
	{
		case 0:
		strcpy (a_psFuncDef->szFunctionName, "Price");
		strcpy (a_psFuncDef->szFunctionDescription, "FirstFunction");
		a_psFuncDef->iNArguments = 0; // число доводов
		break;                                  
		default:
			l_bRtrn = MSX_ERROR;
		break;
	}
  return l_bRtrn;
}

/*
— Шаг 4 – Наша функция

*/

DLL_EXPORT BOOL __stdcall Price(const MSXDataRec *a_psBasic, 
					            const MSXDataInfoRecArgsArray *a_psArrayArgs,
					            const MSXNumericArgsArray *a_psNumericArgs, 
					            const MSXStringArgsArray *a_psStringArgs, 
					            const MSXCustomArgsArray *a_psCustomArgs,  
					            MSXResultRec *a_psResult)

{

// Выводим в наш индикатор Close 
    for (int i= a_psBasic ->sClose.iFirstValid; i<= a_psBasic ->sClose.iLastValid; i  )
        a_psResult->psResultArray->pfValue[ i ] = a_psBasic ->sClose.pfValue[ i ];
// Заменив предыдущую строку на:
//     a_psResult->psResultArray->pfValue[ i ] = float (a_psBasic ->psDate[i].lDate);
// либо
//     a_psResult->psResultArray->pfValue[ i ] = float (a_psBasic ->psDate[i].lTime); 
// соответственно получим дату либо время.

    return MSX_SUCCESS;
}

Дальше в файле UsePrice.def введем дальнейший код:

LIBRARY UsePrice
EXPORTS
  MSXInfo
  MSXNthFunction
  Price
 

Заполняем MSXStruc.h кодом.

MSXStruc.h

#ifndef MSX_Structures_h
#define MSX_Structures_h

/*
  Structures required for MetaStock External Function DLL interface
*/

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

// --------------------------------------------------------------------------
// Return this DLL version constant
// --------------------------------------------------------------------------
const int MSX_VERSION = 1;

// --------------------------------------------------------------------------
// Maximum number of aguments
// --------------------------------------------------------------------------
const int MSX_MAXARGS = 9;

// --------------------------------------------------------------------------
// Maximum string size (does not include MSXString arguments passed in to
//   external functions).
// --------------------------------------------------------------------------
const int MSX_MAXSTRING = 100;

// --------------------------------------------------------------------------
// The following two BOOL return values are returned from MSX functions
// --------------------------------------------------------------------------
const BOOL MSX_SUCCESS = FALSE;
const BOOL MSX_ERROR = TRUE;

// ----------------------------------------------------------------------------------------
// There are four potential argument types
// ----------------------------------------------------------------------------------------
const int MSXDataArray = 0;
const int MSXNumeric   = 1;
const int MSXString    = 2;
const int MSXCustom    = 3;

// ----------------------------------------------------------------------------------------
// The following structure is used by the exported function MSXInfo
// ----------------------------------------------------------------------------------------
typedef struct 
{
	char szCopyright[MSX_MAXSTRING];
	int  iNFuncs;
	int  iVersion;
} MSXDLLDef;

// ----------------------------------------------------------------------------------------
// The following structure is used by the exported function MSXNthFunction
// ----------------------------------------------------------------------------------------
typedef struct 
{
	char  szFunctionName[MSX_MAXSTRING];
	char  szFunctionDescription[MSX_MAXSTRING];
	int   iNArguments;
} MSXFuncDef;

// ----------------------------------------------------------------------------------------
// The following structure is used by the exported function MSXNthArg
// ----------------------------------------------------------------------------------------
typedef struct 
{
	int   iArgType; 
		//  argtype constants:
		//   0 DataArray
		//   1 Numeric
		//   2 String
		//   3 CustomType
	char  szArgName[MSX_MAXSTRING];
	int   iNCustomStrings;
} MSXFuncArgDef;

// ----------------------------------------------------------------------------------------
// The following structure is used by the exported function MSXNthCustomString
// ----------------------------------------------------------------------------------------
typedef struct
{
	char  szString[MSX_MAXSTRING];
	int   iID;
} MSXFuncCustomString;

// ----------------------------------------------------------------------------------------
// the following datastructures are passed into and out of the user-written external
// calculation functions.
// ----------------------------------------------------------------------------------------
typedef struct 
{
	long lDate;
	long lTime;
} MSXDateTime;

typedef struct
{
	float *pfValue;
	int   iFirstValid;
	int   iLastValid;
} MSXDataInfoRec;

typedef struct 
{
	MSXDateTime     *psDate;
	MSXDataInfoRec  sOpen;
	MSXDataInfoRec  sHigh;
	MSXDataInfoRec  sLow;
	MSXDataInfoRec  sClose;
	MSXDataInfoRec  sVol;
	MSXDataInfoRec  sOI;
	MSXDataInfoRec  sInd;
	char            *pszSecurityName; // Security Name
	char            *pszSymbol;       // Security Symbol
	char            *pszSecurityPath; // Path where security is stored (may be in UNC format)
	char            *pszOnlineSource; // Unused - reserved for future use...
	int             iPeriod;          // 'D'aily, 'W'eekly, 'M'onthly, 'Q'uarterly, 'I'ntraday
	int             iInterval;        // For period='I'ntraday only. 0=tick, other value = minutes compression.
	int             iStartTime;       // HHMM format. Undefined for non-intraday period.
	int             iEndTime;         // HHMM format. Undefined for non-intraday period.
	int             iSymbolType;      // Unused - reserved for future use
} MSXDataRec;

typedef struct
{				                                // possible for MSX_MAXARGS data arrays 
	MSXDataInfoRec *psDataInfoRecs[MSX_MAXARGS];  // pointers to the data arrays
	int            iNRecs;                        // number of arrays present (just a sanity check)
} MSXDataInfoRecArgsArray;

typedef struct
{
	float fNumerics[MSX_MAXARGS]; // possible for MSX_MAXARGS numerics
	int   iNRecs;                 // also a sanity check - func knows how many there should be.
} MSXNumericArgsArray;

typedef struct
{
	char *pszStrings[MSX_MAXARGS]; // possible for MSX_MAXARGS strings
	int  iNRecs;                   // ditto the above
} MSXStringArgsArray;

typedef struct
{
	int   iCustomIDs[MSX_MAXARGS]; // numeric ID associated with a custom arg
	int   iNRecs;                  // ditto the above
} MSXCustomArgsArray;

typedef struct
{
	MSXDataInfoRec *psResultArray;     // Pointer to result array
	char           szExtendedError[MSX_MAXSTRING];  // Extended Error string
} MSXResultRec;

#endif

В Visual Studio нажимаем Build -> Build Solution (F6) и получаем нашу DLL. Отправляем ее в папку ‘External Function DLLs’ в Metastock’e и дозволено пользоваться. Наш индикатор будет иметь дальнейший вид:

ExtFml(«UsePrice.Price»)

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

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB