Utilizando Otro Datos de Precios de Intervalo de Tiempo en Indicador (Indicador de Yesterday Close Value)
Contents
¿Por qué se requieren otros datos de intervalo de tiempo?
A veces un indicador requiere datos de un plazo mayor, por ejemplo, podríamos utilizar para cerrar el día anterior para los cálculos. Sin embargo, es posible encontrar estos datos en la historia de precio que se aplica el indicador a, pero… Imagínense. Obtener el high/low de ayer, los todos datos de ayer debe ser cargado. Si la historia actual es una historia de minuto, en el peor de los casos tenemos que tener por lo menos 2880 barras para poder encontrar esos datos (barras de 1440 minuto para hoy y luego barras de 1440 minuto para el conjunto de ayer). Se trata de una enorme cantidad para cargar y, a continuación para calcular. Pero el sistema tiene acceso a los datos de día, así que ¿por qué no lo usamos? Vamos a hacerlo.
Sin embargo, hay algunos puntos que debemos manejar con cuidado. Vale. Vamos a elaborar un indicador que muestra el precio cerca de ayer sobre el gráfico y discutir cada punto en detalle.
¿Qué es “Yesterday”?
El manejo de la fecha en indicadores es bastante simple. Un valor de fecha es un número, que es sólo un número de días pasados medianoche de Dec, 30 1899. También el formato es conocida como formato de la fecha del Windows Ole Automation. La parte entera de este número es que un número de días y la parte fraccionaria es una parte del día. Por lo tanto, para encontrar un calendario de medianoche fecha y hora, sólo debemos piso el valor (cortar la parte fraccionaria). Para cambiar la fecha a N hace días, nosotros sólo debemos restar N desde la fecha. Por lo tanto, si FXCM utilizado el “calendar clock” para los días de comercial (i.e. el día de comercial comienza en medianoche), el hallazgo de ayer para barra x del fuente sería bastante simple: math.floor(source:date(x)) - 1
.
Por desgracia, FXCM’s día de comercial no coincide con el calendario día de comercio. En la actualidad, el día de comercio comienza en 17:00EST ayer y dura hasta 17:00EST hoy. Y para distintas configuraciones puede variar esta fecha. Es de esperar que el núcleo de indicador nos ayuda a manejar el cálculo de las fronteras de vela para una fecha determinada. Hay es una función core.getcandle
que devuelve la fecha y hora de la vela del marco de tiempo especificado para que la fecha y hora pertenecen. Como puede ver, esta función requiere dos parámetros que nos permiten "sintonizar" esta función para una determinada configuración: un día comercial y un desplazamiento de la semana comercial contra el calendario. Debe usa host:execute("getTradingDayOffset")
y
host:execute("getTradingWeekOffset")
host llamadas obtener configuraciones del día de comercio y la semana de comercio para particular aplicación del host y conexión.
Por lo tanto, la función para obtener la fecha de ayer correctamente puede ser la siguiente:
function getYesterday(date)
local offset;
local weekoffset;
offset = core.host:execute("getTradingDayOffset");
weekoffset = core.host:execute("getTradingWeekOffset");
local today, yesterday;
today = core.getcandle("D1", date, offset, weekoffset);
yesterday = today - 1;
return yesterday;
end
¿Buena? Todavía no. Hay otro punto que deberíamos manejar. Hay períodos "no comerciales" cuando ni comercio es posible ni precios son recibidos. Así que, de hecho, durante una semana sólo lunes abrevadero viernes velas existen. No hay en absoluto ninguna velas "Sábado". Así, cuando nuestro minuto pertenece a una vela del día lunes, la función nos devolverá una vela de Domingo que simplemente no existe! Por lo tanto, para los datos del lunes debemos tomar precio cerca del viernes anterior.
Manejar correctamente, hay otra función útil: core.isnontrading
que comprueba si la fecha pertenece a un período de no comerciales (Viernes 17:00EST-Domingo 17:00EST) y devuelve la fecha y tiempo cuando esto período de no comerciales haya terminado. Así, para encontrar la vela adecuada "ayer" tenemos que comprobar si el calendario ayer cae no comerciales período y cambiar la fecha "ayer" en pasado para pasar este período no comerciales.
Debemos modifica nuestra función un poco:
function getYesterday(date)
local offset;
local weekoffset;
offset = core.host:execute("getTradingDayOffset");
weekoffset = core.host:execute("getTradingWeekOffset");
local today, yesterday;
today = core.getcandle("D1", date, offset, weekoffset);
yesterday = today - 1;
local nontrading, nontradingend;
nontrading, nontradingend = core.isnontrading(yesterday, offset);
if nontrading then
-- if the calendar yesterday date is non-trading (Friday 17:00 EST - Sunday 17:00 EST)
-- shift three days back against the non-trading period end (Sunday 17:00 EST).
yesterday = nontradingend - 3;
end
return yesterday;
end
Por lo tanto, ahora, tengan la función getYesterday()
podemos más fácil encuentra cómo muchos días necesitamos. El día más viejo es getYesterday(source:date(source:first()))
, i.e. la barra de “yesterday” que corresponde a la antigua barra disponible. ¿Y uno más reciente? Hay dos casos. La colección de origen podría ser bien un histórico (i.e. una colección cargada hasta la fecha especificada, que nunca cambiará para la ventana de gráfico) o “alive” (i.e. cargado hasta “now” y creciendo continuamente nuevas barras vienen). Según estos casos, la fecha “to” podría ser un día de “yesterday” del más reciente barra disponible (getYesterday(source:date(source:size() - 1))
o … ahora tan bien. Especificar “now”, usamos el valor 0
.
Cargando los Datos
Utilizando Host Cargar Datos
OK, ahora sabemos que los datos que necesitamos. El siguiente paso es conseguir estos datos. Marketscope proporciona una interfaz host
que permite ejecuta unas funciones de interface específica de la aplicación. Uno de estos funciones es “getHistory”
. Por este llame Marketscope carga el instrumento en el intervalo de tiempo especificado y en el rango de tiempo especificado. Véase host:execute(“getHistory”, …)
para detalles.
local days; -- a variable to keep days
-- the function loads the proper day history
function loadData()
if source:size() < source:first() then
return ;
end
local from, to;
-- load the data from the date of proper yesterday for
-- the first available bar of the source
from = getYesterday(source:date(source:first()));
-- load to "now" if the source is up to "now" or
-- to the day which corresponds to the latest
-- day of the collection.
if source:isAlive() then
to = 0;
else
to = getYesterday(source:date(source:size() – 1));
end
days = host:execute("getHistory", 1, source:instrument(), "D1", from, to, source:isBid());
end
Este importante que después de la llame “getHistory”
, Marketscope sólo starts cargar los datos. Toma algún tiempo, pero Marketscope no espere a que los datos están completamente cargados evitar colgantes del indicador. Cuando cargando de los datos se finalizado, Marketscope notificará el indicador por llamar a la función AsyncOperationFinished
. Además, Marketscope no se preocupan por el estado del indicador y continuará llamando indicador actualizarse.
Por lo tanto, hay dos puntos que hacer.
Proteger Indicador desde Actualización Mientra los Datos Se Carga
En primer lugar, debemos proteger el indicador de actualización mientras se cargan los datos.
Proteger el indicador de ser recalculado, sólo podemos volver desde la función de actualiza mientra mientras se está cargando los datos. Sólo anida la variable global “loading” por lo tanto que todas funciones podría “know” que datos se está cargando.
local days; -- day source data
local loading; -- the loading day data flag
function Prepare()
...
days = nil;
loading = false;
...
end
function Update(period, mode)
if loading then
-- do nothing if data is being loaded
return ;
end
if days == nil then
loadData();
return ;
end
...
end
function AsyncOperationFinished(cookie, success, error)
if cookie == 1 then
assert(success, error);
loading = false;
end
return 0;
end
function loadData()
if loading then
return ;
end
local from, to;
-- load the data from the date of proper yesterday for
-- the first available bar of the source
from = getYesterday(source:date(source:first()));
-- load to "now" if the source is up to "now" or
-- to the day which corresponds to the latest
-- day of the collection.
if source:isAlive() then
to = 0;
else
to = getYesterday(source:date[source:size() - 1]);
end
loading = true;
days = host:execute("getHistory", 1, source:instrument(), "D1", from, to, source:isBid());
end
Forzando Actualiza Cuando Datos Se Carga
Ahora bien, tenemos que forzar la actualización de indicador cuando se cargan los datos. Existe una función instance:updateFrom()
que fuerza el indicador ser recalculado desde el período especificado. También cuando AsyncOperationFinished
devuelve el valor core.ASYNC_REDRAW
, Marketscope redibuja el indicador en la ventana del gráfico.
Así, pues no hemos calculado nada aún, tenemos que actualizar nuestro indicador desde los datos más antiguos. Arreglarlo AsyncOperationFinished
un poco.
function AsyncOperationFinished(cookie, success, error)
if cookie == 1 then
assert(success, error);
loading = false;
instance:updateFrom(source:first());
return core.ASYNC_REDRAW;
end
return 0;
end
Obtenido Datos
Casi terminado. La última pregunta es cómo obtener los datos. Podemos calcular la fecha del día. Por supuesto, nosotros podemos simplemente recorrer la historia del día y averiguar la fecha, pero… Es un poco largo, ¿no? Sin embargo, hay una función que se encuentra la fecha sólo para log2(n) operations - core.findDate()
.
Por lo tanto, podemos construir la primera versión de nuestra indicador. Vamos a hacerlo y probarlo.
function Init()
indicator:name("Show Yesterday Close");
indicator:description("The indicator shows yesterday's close value on the chart");
indicator:requiredSource(core.Tick);
indicator:type(core.Indicator);
indicator.parameters:addColor("clr", "Indicator Line Color", "", core.rgb(255, 255, 0));
end
local source; -- indicator source data
local first; -- first available source data
local days; -- day source data
local loading; -- the loading day data flag
local loadedFrom; -- the date from which the days was loaded
local SYC; -- yesterday close output
local host;
local offset;
local weekoffset;
function Prepare()
local name;
name = profile:id() .. "(" .. instance.source:name() .. ")";
instance:name(name);
source = instance.source;
first = source:first();
loading = false;
days = nil;
host = core.host;
offset = host:execute("getTradingDayOffset");
weekoffset = host:execute("getTradingWeekOffset");
SYC = instance:addStream("SYC", core.Line, name, "SYC", instance.parameters.clr, first);
end
function Update(period, mode)
if period < first then
return ;
end
if loading then
return ;
end
-- load the data if there is no day
if days == nil then
SYC:setBookmark(1, source:first());
loadData();
return ;
end
-- try to find the value in the days collection
local yesterday;
yesterday = getYesterday(source:date(period));
if yesterday < loadedFrom then
SYC:setBookmark(1, period);
loadData();
return ;
end
local i;
i = core.findDate(days, yesterday, false);
if i >= 0 then
SYC[period] = days.close[i];
end
end
function AsyncOperationFinished(cookie, success, error)
if cookie == 1 then
assert(success, error);
loading = false;
local i = SYC:getBookmark(1);
if i < source:first() then
i = source:first();
end
instance:updateFrom(i);
return core.ASYNC_REDRAW;
end
return 0;
end
-- the function loads the proper day history
function loadData()
if source:size() < source:first() then
return ;
end
if loading then
return ;
end
local from, to;
if days == nil then
-- initial data loading
-- load the data from the date of proper yesterday for
-- the first available bar of the source
from = getYesterday(source:date(source:first()));
-- load to "now" if the source is up to "now" or
-- to the day which corresponds to the latest
-- day of the collection.
if source:isAlive() then
to = 0;
else
to = getYesterday(source:date(source:size() - 1));
end
loading = true;
loadedFrom = from;
days = host:execute("getHistory", 1, source:instrument(), "D1", from, to, source:isBid());
else
from = getYesterday(source:date(source:first()));
to = days:date(0);
loading = true;
loadedFrom = from;
host:execute("extendHistory", 1, days, from, to);
end
end
-- returns the beginning of the "yesterday" date for
-- the specified date
function getYesterday(date)
local today, yesterday;
-- get beginning of the today's candle and round it up to the second
today = core.getcandle("D1", date, offset, weekoffset);
today = math.floor(today * 86400 + 0.5) / 86400;
-- get calendar yesterday
yesterday = today - 1;
local nontrading, nontradingend;
nontrading, nontradingend = core.isnontrading(yesterday, offset);
if nontrading then
-- if the calendar yesterday date is non-trading (Friday 17:00 EST - Sunday 17:00 EST)
-- shift three days back against the non-trading period end (Sunday 17:00 EST).
yesterday = nontradingend - 3;
end
return yesterday;
end
Ahora aplica el indicador a el gráfico.
Funciona!!!! Pero parada, parada, stop… Cuando intentamos cargar más datos en pasado aparentemente dejó de trabajar!
Cómo Procesar Scroll Back
¡¿Qué ha pasado?! Vale. Recuerde, cargan los datos a partir de ayer para la más antigua de las velas existentes. Cuando empezamos a desplazarsenuestra espalda gráfico, más datos se cargó. ¿Pero quien ha actualizado nuestra colección de barras de día? Por supuesto, nadie lo hizo. Por lo tanto, tenemos que forzar Marketscope
cargar nuevos datos cuando la colección de origen se extiende en pasado. Buena noticia es que hay otra llame de cool de la interfaz de host:
host:execute(“extendHistory”)
que nos ayuda a cargar sólo los datos más en ya cargado historia en vez de cargando las todas historia nuevo. Porque historia puede ser extendido sólo en pasado, es demasiado fácil comprobar si se cargan los datos nuevos. Cuando ocurre, el valor “yesterday” estamos tratando de encontrar es anterior a la fecha hemos cargado previamente la historia del día de.
Por lo tanto, hacer la siguiente modificación en nuestro código:
- Mantiene la fecha “from” cargamos la historia del día anterior.
- En el caso de la colección de día ya existe, ampliarlo en lugar de cargar los datos más antiguos.
Por lo tanto, anida nuevo loadedFrom
variable global. Y cambia las funciones de Update
y loadData
.
Hay una nueva versión de indicador:
function Init()
indicator:name("Show Yesterday Close");
indicator:description("The indicator shows yesterday's close value on the chart");
indicator:requiredSource(core.Tick);
indicator:type(core.Indicator);
indicator.parameters:addColor("clr", "Indicator Line Color", "", core.rgb(255, 255, 0));
end
local source; -- indicator source data
local first; -- first available source data
local days; -- day source data
local loading; -- the loading day data flag
local loadedFrom; -- the oldest yesterday bar we already loaded
local SYC; -- yesterday close output
local host;
local offset;
local weekoffset;
function Prepare()
local name;
name = profile:id() .. "(" .. instance.source:name() .. ")";
instance:name(name);
source = instance.source;
first = source:first();
loading = false;
days = nil;
host = core.host;
offset = host:execute("getTradingDayOffset");
weekoffset = host:execute("getTradingWeekOffset");
SYC = instance:addStream("SYC", core.Line, name, "SYC", instance.parameters.clr, first);
end
function Update(period, mode)
if period < first then
return ;
end
if loading then
return ;
end
-- load the data if there is no day
if days == nil then
loadData();
return ;
end
-- try to find the value in the days collection
local yesterday;
yesterday = getYesterday(source:date(period));
-- check whether such day bar is not loaded yet
if yesterday < loadedFrom then
loadData();
return ;
end
-- find the day data
local i;
i = core.findDate(days, yesterday, false);
if i >= 0 then
SYC[period] = days.close[i];
end
end
function AsyncOperationFinished(cookie, success, error)
if cookie == 1 then
assert(success, error);
loading = false;
instance:updateFrom(source:first());
return core.ASYNC_REDRAW;
end
return 0;
end
-- the function loads the proper day history
function loadData()
if source:size() < source:first() then
return ;
end
if loading then
return ;
end
local from, to;
if days == nil then
-- initial data loading
-- load the data from the date of proper yesterday for
-- the first available bar of the source
from = getYesterday(source:date(source:first()));
-- load to "now" if the source is up to "now" or
-- to the day which corresponds to the latest
-- day of the collection.
if source:isAlive() then
to = 0;
else
to = getYesterday(source:date(source:size() - 1));
end
loading = true;
loadedFrom = from;
days = host:execute("getHistory", 1, source:instrument(), "D1", from, to, source:isBid());
else
from = getYesterday(source:date(source:first()));
to = days:date(0);
loading = true;
loadedFrom = from;
host:execute("extendHistory", 1, days, from, to);
end
end
-- returns the beginning of the "yesterday" date for
-- the specified date
function getYesterday(date)
local today, yesterday;
-- get beginning of the today's candle and round it up to the second
today = core.getcandle("D1", date, offset, weekoffset);
today = math.floor(today * 86400 + 0.5) / 86400;
-- get calendar yesterday
yesterday = today - 1;
local nontrading, nontradingend;
nontrading, nontradingend = core.isnontrading(yesterday, offset);
if nontrading then
-- if the calendar yesterday date is non-trading (Friday 17:00 EST - Sunday 17:00 EST)
-- shift three days back against the non-trading period end (Sunday 17:00 EST).
yesterday = nontradingend - 3;
end
return yesterday;
end
Instala el indicador y probarlo. Wow. Ahora, cuando la versión anterior dejó de funcionar durante el desplazamiento, la nueva versión funciona de todos modos! ¡ Felicidades!
Notas
Cómo Depurar Tales Indicadores Utilizando Using SDK Debugger?
Primera, debe prepara los datos. Puede guarda archivos de los datos de precio utilizando Marketscope. Simplemente abra algún instrumento en ambas resoluciones (por ejempl 30 minutos y 1 día) y a continuación guarda los dos historias en el formato de datos de Indicore SDK (File->Export to Indicore…). También puede descargar los datos automáticamente a través de SDK Debugger utilizando el servidor del quotes manager (Tools->Load Quotes).
Cuando comienza el indicador, elija el la historia de timeframe más pequeña en los parámetros del indicador. También, por favor comprueba el casilla de verificación de “Predeliver Data” en los parámetros del indicador permitir el debugger muestra los todos historia disponible a el indicador, como Marketscope hace. Sin este opción, el debugger sólo mostrará la historia sólo hasta el bar actualmente simulado. Cuando el indicador ejecuta la llamada “getHistory”
, el prompt para datos aparece. Elija los datos de día guardado anteriormente desde Marketscope en que prompt o usa datos desde el servidor del quotes manager.
¿Cómo Controlar Timeframes Distinto 1 Día?
Hacer el indicador de ejemplo más simple, utiliza un intervalo de tiempo de 1-día. Sin embargo, desea hacer lo mismo para los otros datos de intervalo de tiempo, por ejemplo, usa 1-hora precio de cierre en vez de una día de precio cierre. Para ello, puede:
- Permiten al usuario elegir el intervalo de tiempo. Agregar un parámetro de cadena a la lista de parámetros de indicadores y, a continuación, establecer el indicador de selector de plazos para ese parámetro. Como resultado, en la función de preparación, el parámetro correspondiente contendrá el código del marco de tiempo elegido por el usuario.
function Init()
...
indicator.parameters:addString("TF", "Timeframe", "", "m1");
indicator.parameters:setFlag("TF", core.FLAG_PERIODS);
...
end
- Calcula la longitud de una vela del intervalo de tiempo especificado en día. Usa la función [c]core.getcandle()[/c] obtener la fecha de inicio de algún vela y la fecha de inicio del siguiente vela. La diferencia entre estos dos valores es la longitud de la vela en días. Recomiendo también calcular todas las fechas en segundos en vez de días para evitar errores de redondeo.
local candleLength; -- length of candle in seconds
function Prepare()
...
offset = host:execute("getTradingDayOffset");
weekoffset = host:execute("getTradingWeekOffset");
...
local thisCandle, nextCandle;
thisCandle, nextChandle = core.getcandle(instance.parameters.TF, core.now(), offset, weekoffset);
candleLength = math.floor((nextCandle - thisCandle) * 86400 + 0.5);
...
end
- Utilizar la longitud de vela calculada anteriormente en vez del valor de 1 día en su función “getPreviousBar”. Por favor nota que mientra la longitud de la vela podría ser diferente, el período de no comerciales está aún en días. Por lo tanto, manejar con cuidado.
function getPreviousBar(date)
local curr, prev;
-- get beginning of the today's candle and round it up to the second
curr = core.getcandle(instance.parameters.TF, date, offset, weekoffset);
today = math.floor(today * 86400 + 0.5);
-- get calendar yesterday
prev = (curr – candleLength) / 86400;
local nontrading, nontradingend;
nontrading, nontradingend = core.isnontrading(prev, offset);
if nontrading then
prev = prev - 2;
prev = math.floor(prev * 86400 + 0.5);
-- get calendar yesterday
prev = (prev – candleLength) / 86400;
end
return prev;
end
Este Artículo en Otros Idiomas
Language: | English • español • français • русский • 中文 • 中文(繁體) |
---|