Módulos de Extensión de Lua

From FxCodeBaseWiki
(Redirected from Lua Extension Modules/es)
Jump to: navigation, search

¿Qué Es Módulos de Extensión de Lua?

El Lua Extension Module es una biblioteca de de vínculos dinámicos que contiene el conjunto de funciones escrito en C o C++ que puede utilizarse desde código de Lua.

El artículo supone que está familiarizado con el Lua VM y desarrollo utilizando Lua VM. Puede leer sobre Lua VM en Lua documentación, Section 3. The Application Program Interface.

Por favor tenga en cuenta que Lua Extension Module se puede desarrollar sólo en C o C++. Este artículo supone que utiliza Microsoft Visual Studio, pero cualquier compilador de Win32 C++ puede utilizarse en vez de.

¿Cómo Comenzar?

Preparar el Entorno

Todo lo que necesita descargar y instalar el último versión del Indicore Integration SDK. El último versión siempre es disponible aquí: IndicoreDev.exe

Creación del Proyecto

  • Crea un nuevo projecto de C++/Win32.
  • Elija tipo de aplicación DLL y crea un proyecto vacío
  • En los opciones de linker, sección de "Input" anida C:\Gehtsoft\IndicoreDev\lib\lua5.1.lib y C:\Gehtsoft\IndicoreDev\lib\indicore2.lib a propriedad de Additional Dependencies.
  • El nombre de archivo de salida debe ser exactamente el mismo como el nombre de la tabla de extensión que va utilizar. En nuestro caso vamos implementar la función de valor de la media geométrica para Lua, así que vamos a se denomina módulo de salida geomean.dll.

Archivos de Encabezado

Anida los encabezados siguientes en su archivo de origen:

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <tchar.h>
#include <string>
#include <vector>
#include <map>
#include <list>
#define INDICORE2_EXTKIT
#include "C:/Gehtsoft/IndicoreDev/include/indicore2.h"

Escribir la Plantilla de la Función de Extensión

A continuación, debe crear una plantilla de función de la extensión. Todos la funcion de extension tiene exactamente el mismo prototype. Puede utiliza cualquier nombre pero la estila buena es utilizar el nombre que es similar a el nombre queremos utilizar.

/** The geomean.calc(stream, from, to). 

    stream the tick stream
    from   the first period of the range to calculate
    to     the last period of the range to calculate

    The function return the geometric mean value (1 number)
  */
int geomean_calc(lua_State *L)
{
    double ret = 0;
    //TBD: Calculate mean value into ret variable
  
    lua_pushnumber(L, ret);
    return 1;
}

Crear Descripción del Módulo

Ahora debemos crea una descripción de la tabla módulo de extensión. La tabla módulo de extensión es una matriz de luaL_reg estructuras. Cada elemento de matriz corresponde a una función y defina el nombre de la función como es visible en lua. El último elemento debe ser una estructura llenado por ceros.

static const struct luaL_reg geomean_lib [] =
{
     {"calc", geomean_calc},
     {NULL, NULL}
};

Crear la Función del Módulo de Registro

Ahora debemos crear una función exportable que se llamará cuando Lua se pide cargar cargar nuestro módulo de extensión. El nombre de este función debe crearse utilizando el siguiente patrón: luaopen_name donde name es el nombre del módulo de extensión (geomean in our case).

extern "C" int __declspec(dllexport) luaopen_extension (lua_State *L)
{
    luaL_register(L, "geomean", geomean_lib);

    lua_getglobal(L, "geomean");
    if (lua_isnil(L, -1) || !lua_istable(L, -1)) {
        luaL_error(L, "the geomean library is not registered");
    }
    return 1;
}

Preparar el Indicador de Prueba

El indicador es muy similar a un indicador de simple moving average (MVA.lua). sólo se necesita un entero parámetro N (un número de períodos), puede aplicarse en los datos de tick y se puede calcular, empezando en barra de Nth. Vamos a crea el esqeleto de indicador. Para para indicador de información sobre el indicador de escritura por favor consulte el Indicore SDK, especialmente el instrucción de paso a poso en creación de un indicador sencillo.

function Init()
    indicator:name("Test indicator");
    indicator:description("");
    indicator:requiredSource(core.Tick);
    indicator:type(core.Indicator);

    indicator.parameters:addGroup("Calculation");
    indicator.parameters:addInteger("N", "Number of periods", "", 10, 2, 1000);
    indicator.parameters:addGroup("Style");
    indicator.parameters:addColor("C", "Line Color", "", core.rgb(0, 0, 255));
    indicator.parameters:addInteger("W", "Line Width", "", 1, 1, 5);
    indicator.parameters:addInteger("S", "Line Style", "", core.LINE_SOLID);
    indicator.parameters:setFlag("S", core.FLAG_LEVEL_STYLE);
end

local n;
local first = nil;
local source = nil;
local out = nil;

require("geomean");

function Prepare(onlyName)
    local name;

    name = profile:id() .. "(" .. instance.source:name() .. ")";
    instance:name(name);
    if onlyName then
        return ;
    end

    source = instance.source;

    n = instance.parameters.N;
    first = source:first() + n - 1;
    out = instance:addStream("GEOMEAN", core.Line, name, "GEOMEAN", instance.parameters.C, first);
    out:setWidth(instance.parameters.W);
    out:setStyle(instance.parameters.S);
end

function Update(period, mode)
    if period >= first then
        out[period] = geomean.calc(source, period - n + 1, period);
    end
end

Preste atención en las líneas de resaltado. The first forces Lua to load our extension. The second is a call of our function.

Función de Extensión de Aplicación

Ahora podemos implementar la función de extensión. En primer lugar, debemos obtener los parámetros de la pila. Como vea desde el código de indicador, el primero parámetro es una secuencia. Por lo que, necesitamos saber cómo convertir la tabla de Lua table en interfaz IIndicatorTickSource. Es por ello que Indicore Integration SDK se requiere en este proyecto particular. Tiene clase IndicoreAccessors diseñado para tal fin.

Así, obtener los valores de parámetro de la pila y compruebe los tipos.

/** The geomean.calc(stream, from, to). 

    stream the tick stream
    from   the first period of the range to calculate
    to     the last period of the range to calculate

    The function return the geometric mean value (1 number)
  */
int geomean_calc(lua_State *L)
{
    double ret = 0;

    IIndicatorTickSource *src = IndicoreAccessors::getIIndicatorTickSource(L, 1);
    if (src == 0)
        return luaL_error(L, "the first parameter must be source.");

    if (lua_isnumber(L, 2) == 0)
        return luaL_error(L, "the second parameter must be number");
    int from = (int)lua_tonumber(L, 2);

    if (lua_isnumber(L, 3) == 0)
        return luaL_error(L, "the third parameter must be number");
    int to = (int)lua_tonumber(L, 3);
  
    lua_pushnumber(L, ret);
    return 1;
}

Ahora, comprueba los parámetros de desde y a. Ambos de ellos deben ser en el rango de los datos de origen de precio y a debe ser después desde.

/** The geomean.calc(stream, from, to). 

    stream the tick stream
    from   the first period of the range to calculate
    to     the last period of the range to calculate

    The function return the geometric mean value (1 number)
  */
int geomean_calc(lua_State *L)
{
    double ret = 0;

    IIndicatorTickSource *src = IndicoreAccessors::getIIndicatorTickSource(L, 1);
    if (src == 0)
        return luaL_error(L, "the first parameter must be source.");

    if (lua_isnumber(L, 2) == 0)
        return luaL_error(L, "the second parameter must be number");
    int from = (int)lua_tonumber(L, 2);

    if (lua_isnumber(L, 3) == 0)
        return luaL_error(L, "the third parameter must be number");
    int to = (int)lua_tonumber(L, 3);

    if (from < src->getFirstPeriod() || from >= src->size() ||
        to < src->getFirstPeriod() || to >= src->size())
        return luaL_error(L, "the period index is out of range");

    if (to <= from)
        return luaL_error(L, "the third parameter must be greater than the second");

  
    lua_pushnumber(L, ret);
    return 1;
}

Ahora implementa la calculación de la media geométrica. La fórmula de la media geométrica del valor de n value es:

<math>\operatorname{geomean}(price, n)_i = \sqrt[n]{\prod_{j=i-n+1}^i price_j} = ({\prod_{j=i-n+1}^i price_j})^{\frac{1}{n}}</math>

/** The geomean.calc(stream, from, to). 

    stream the tick stream
    from   the first period of the range to calculate
    to     the last period of the range to calculate

    The function return the geometric mean value (1 number)
  */
int geomean_calc(lua_State *L)
{
    double ret = 0;

    IIndicatorTickSource *src = IndicoreAccessors::getIIndicatorTickSource(L, 1);
    if (src == 0)
        return luaL_error(L, "the first parameter must be source.");

    if (lua_isnumber(L, 2) == 0)
        return luaL_error(L, "the second parameter must be number");
    int from = (int)lua_tonumber(L, 2);

    if (lua_isnumber(L, 3) == 0)
        return luaL_error(L, "the third parameter must be number");
    int to = (int)lua_tonumber(L, 3);

    if (from < src->getFirstPeriod() || from >= src->size() ||
        to < src->getFirstPeriod() || to >= src->size())
        return luaL_error(L, "the period index is out of range");

    if (to <= from)
        return luaL_error(L, "the third parameter must be greater than the second");

    double n = (double)(to - from + 1);
    double prod = 1;

    for (int i = from; i <= to; i++)
        prod *= src->getTick(i);

    ret = pow(prod, 1.0 / n);

    lua_pushnumber(L, ret);
    return 1;
}

Eso es todo la extensión se completa. Sólo compilarlo.

Implementación y Pruebas

  • Pone compilado geomean.dll en la misma carpeta de la aplicación (por ejemplo Marketscope o Indicator Debugger) donde lua5.1.dll se encuentra (usualmente, es la carpeta donde se instala la aplicación);
  • Instala el indicador;
  • Ejecuta indicador.

Problemas Conocidos

Excepciones de C++

El versión utilizado de LuaJIT tiene no apoyo para C++ excepciones para código de Microsoft Visual C++/Win32. Por lo que, tampoco debe utilizar try/catch derecho en la función que se llama desde Lua, nor llamarlo Lua desde dentro de bloque de try/catch. Véase también sobre que problema: LuaJIT documentation, Discussion thread

Este Artículo en Otros Idiomas

Language: English  • español • français • русский • 中文 • 中文(繁體)‎