En el capítulo sobre cruces, el indicador dibujaba una señal al cruzarse las medias. Ahora usarás el mismo evento para activar una orden simulada. El programa abre una posición larga en el cruce ascendente y la cierra en el descendente.

¿Qué hace una estrategia?

Un indicador calcula y representa. Una estrategia también envía órdenes al simulador de backtest. Este sigue las órdenes, posiciones y resultados a partir de velas históricas y las reglas indicadas.

Esta prueba histórica se llama backtest. Todas las órdenes de este capítulo son simuladas; Run Pyne code no envía órdenes a una cuenta real de trading.

Una posición es la exposición que existe después de ejecutarse una entrada. La orden es la instrucción; la ejecución es el evento que crea o modifica la posición. No utilizamos estos términos de forma intercambiable.

Primero, las reglas por escrito

Las reglas de esta estrategia:

  • Calcula SMA de cinco y veinte en cada vela.
  • En el cruce ascendente envía una orden de entrada larga de una unidad.
  • En el descendente cierra la posición asociada a la entrada Long.
  • Los cálculos usan datos de velas históricas cerradas.

Una posición larga gana valor cuando el precio sube y lo pierde cuando baja. En este ejemplo no abrimos posiciones cortas.

La regla no dice que todos los cruces ascendentes sean rentables. El backtest examina precisamente qué habría ocurrido en esos datos con esas operaciones.

El programa completo

Crea crossover_strategy.py:

"""
@pyne edge
"""
from pynecore.lib import close, color, input, plot, script, strategy, ta


@script.strategy(
    "Average Crossing Strategy",
    overlay=True,
    initial_capital=10000,
    default_qty_type=strategy.fixed,
    default_qty_value=1,
    pyramiding=1,
)
def main(
    fast_length: int = input.int(5, title="Fast length", minval=1, maxval=200),
    slow_length: int = input.int(20, title="Slow length", minval=1, maxval=200),
):
    fast_average = ta.sma(close, fast_length)
    slow_average = ta.sma(close, slow_length)
    crosses_up = ta.crossover(fast_average, slow_average)
    crosses_down = ta.crossunder(fast_average, slow_average)
    if crosses_up:
        strategy.entry("Long", strategy.long)
    if crosses_down:
        strategy.close("Long")
    plot(fast_average, "Fast average", color=color.blue, linewidth=2)
    plot(slow_average, "Slow average", color=color.orange, linewidth=2)

@script.strategy indica que main() es una estrategia. Los cálculos y las dos líneas siguen utilizándose. La nueva importación, strategy, contiene las operaciones de órdenes y los datos de la estrategia.

El decorador es una llamada de varias líneas. Sus ajustes controlan la ejecución de la estrategia; los parámetros de main() son las entradas de nuestros cálculos.

Capital inicial y cantidad

initial_capital=10000 establece el saldo inicial de la simulación. Los metadatos de mercado de la demostración determinan sus unidades y niveles de precios.

default_qty_type=strategy.fixed significa cantidad fija. default_qty_value=1 pide una orden de una unidad. No es el uno por ciento del capital ni necesariamente una unidad monetaria.

pyramiding=1 permite como máximo una entrada en la misma dirección. El ejemplo no aumenta la posición existente con más entradas largas.

Para aprender seguimos las operaciones con una cantidad pequeña y fija. Así hay menos factores de dimensionamiento que examinar a la vez cuando cambia el resultado.

Los identificadores de entrada y cierre

El primer argumento de strategy.entry("Long", strategy.long) identifica la orden. El programa elige el texto Long; el segundo argumento define la dirección.

strategy.close("Long") se refiere al mismo identificador. Deben coincidir. Si entras con "Buy", cerrar "Long" no apunta a esa entrada.

El cruce descendente es aquí un cierre, no una entrada corta. Si no existe una posición abierta con ese nombre, no hay nada que cerrar.

Ejecución en PyneIDE

  1. Guarda el programa completo.
  2. Selecciona Run Pyne code y los datos demo.
  3. Comprueba las líneas SMA y las marcas de operaciones en el gráfico.
  4. Abre el panel inferior y elige Trades.
Junto a crossover_strategy.py se ven las dos SMA y las marcas de entrada y salida de la estrategia.
Los cruces de SMA activan órdenes; las operaciones ejecutadas también aparecen en el gráfico.

Si no ves operaciones, comprueba que ejecutaste el archivo de estrategia y conservaste @script.strategy. Revisa los valores efectivos de los inputs. Las SMA de igual longitud calculadas sobre la misma fuente no se cruzan.

El momento de la señal y de la ejecución

Con los ajustes predeterminados de aquí, el programa genera una orden de mercado con los datos de cierre. Normalmente se ejecuta en la apertura de la siguiente vela. Por eso la vela de señal y la de entrada pueden diferir.

Lo mismo vale para el cierre de mercado. La orden creada en el cruce descendente puede cerrar la posición en la siguiente apertura.

Si la última vela genera una orden, no hay otra después en el archivo. Puede quedar sin ejecutarse. Una posición abierta antes también puede seguir abierta al terminar los datos.

El modo de ejecución forma parte de los ajustes. En el siguiente capítulo lo veremos en Properties. Interpreta cada resultado con el modo que se utilizó para obtenerlo.

Pruébalo por tu cuenta

Abre los inputs y pon ambas longitudes en 20. Predice dos cosas: cómo se situarán las líneas y cuántos cruces podrán originar operaciones.

Solución del ejercicio

Las SMA usan los mismos precios y la misma ventana, así que coinciden. No hay una vela donde una pase por encima o por debajo de la otra. La estrategia no abre operaciones con esta regla.

El gráfico mostrará ese resultado cuando guardes los inputs modificados y termine el recálculo. Después de comprobarlo, restaura 5 y 20.

Selecciona una entrada

Busca una entrada ejecutada y examina las medias en la vela anterior. El cruce ascendente debe cumplirse en la vela de señal. Compara el precio de la operación con la apertura de la vela de entrada, no automáticamente con el cierre de la señal.