IDE: órdenes y salidas

Abrir y cerrar posiciones, calcular el tamaño, poner stops y take-profits, y escribir condiciones de entrada.

La API de trading dentro de on_bar() en el IDE
La API de trading dentro de on_bar(): self.buy / self.sell para abrir, self.close() para cerrar y self.log() para dejar rastros.

Aquí está la API para operar desde tu código: abrir posiciones largas o cortas, dimensionarlas correctamente, asignarles stops y objetivos, y cerrarlas cuando quieras. Todos los métodos están disponibles dentro de tu clase de estrategia.

Abrir una posición

`self.buy(...)` abre una posición larga (compra) y `self.sell(...)` abre una posición corta (venta). Ambos métodos aceptan los mismos argumentos para dimensionar y fijar salidas.

python
self.buy(sl_atr=1.5, tp_atr=3.0)    # largo con SL a 1.5*ATR y TP a 3*ATR
self.sell(sl_atr=1.5, tp_atr=3.0)   # corto
Las unidades de sl_atr y tp_atr son múltiplos del ATR calculado en cada barra.

Tamaño de la posición (obligatorio elegir uno)

Debes indicar cómo se calcula el tamaño de cada orden con uno de estos tres argumentos. Si no incluyes ninguno, la orden no sabe cuánto arriesgar y no se ejecutará.

ArgumentoQué haceEjemplo
lots=0.1Lotes fijos, sin importar el balance ni la volatilidad.lots=0.05
risk_pct=0.02Arriesga el 2% del balance. Calcula los lotes automáticamente según la distancia al SL.risk_pct=0.01
risk_usd=100Arriesga exactamente 100 USD fijos por operación.risk_usd=50
python
self.buy(sl_atr=1.5, tp_atr=3.0, lots=0.1)
self.buy(sl_atr=1.5, tp_atr=3.0, risk_pct=0.02)
self.buy(sl_atr=1.5, tp_atr=3.0, risk_usd=100)
Elige solo uno de los tres. Combinarlos generará un error de validación.

`risk_pct` es lo más recomendable: mantiene el riesgo constante aunque cambie el balance o la volatilidad del instrumento. También existe `self.sizer` con métodos `fixed`, `risk_percent`, `risk_currency` y `kelly` para cálculos avanzados de lotaje cuando necesites lógica más elaborada.

Stops y take-profits: modos de salida

Por defecto se usan múltiplos de ATR con `sl_atr` y `tp_atr`, pero puedes pasar un argumento `exit_mode` para cambiar el comportamiento de salida. Cada modo tiene sus propios parámetros.

ModoPara quéParámetros
atr (por defecto)SL y TP en múltiplos del ATR actual.sl_atr, tp_atr
fixed_pipsDistancias fijas en pips.slPips, tpPips
percentSL y TP como porcentaje del precio de entrada.slPct, tpPct
trailing_atrTrailing stop que persigue al precio a medida que sube.trailAtr
breakevenMueve el SL al precio de entrada cuando la posición gana X ATR.beActivationAtr (+ sl_atr, tp_atr para el SL/TP inicial)
structureSL en el mínimo (o máximo para cortos) de las últimas N velas.lookback (+ tp_atr para el objetivo)
time_exitCierra la posición automáticamente tras N velas.maxBars (+ sl_atr para protección)
partial_tpCierra un porcentaje de la posición en TP1, el resto en TP2.tp1Atr, tp2Atr, partialPct
python
# ATR (por defecto)
self.buy(sl_atr=1.5, tp_atr=3.0)

# Pips fijos
self.buy(exit_mode={"type": "fixed_pips", "slPips": 20, "tpPips": 40})

# Porcentaje del precio
self.buy(exit_mode={"type": "percent", "slPct": 1.0, "tpPct": 2.0})

# Trailing stop (persigue al precio)
self.buy(exit_mode={"type": "trailing_atr", "trailAtr": 1.5})

# Breakeven (mueve el SL a entrada al ganar X*ATR)
self.buy(exit_mode={"type": "breakeven", "beActivationAtr": 1.0}, sl_atr=2.0, tp_atr=4.0)

# Estructura (SL en el mínimo de las últimas N velas)
self.buy(exit_mode={"type": "structure", "lookback": 10}, tp_atr=3.0)

# Salida por tiempo (cierra tras N velas)
self.buy(exit_mode={"type": "time_exit", "maxBars": 20}, sl_atr=2.0)

# TP parcial (cierra parte en TP1, resto en TP2)
self.buy(exit_mode={"type": "partial_tp", "tp1Atr": 1.5, "tp2Atr": 3.0, "partialPct": 50})
Puedes combinar exit_mode con sl_atr/tp_atr cuando el modo lo requiera (por ejemplo, breakeven necesita un SL inicial).

Cerrar posiciones

MétodoQué cierra
self.close()La primera posición abierta.
self.close(position_id=N)Una posición concreta identificada por su ID.
self.close_all()Todas las posiciones abiertas.
self.close_longs()Solo las posiciones largas (compras).
self.close_shorts()Solo las posiciones cortas (ventas).
self.get_position(id)Devuelve el objeto de una posición abierta por su ID.
self.get_positions_by_tag(tag)Devuelve todas las posiciones que tengan la etiqueta indicada.

Escribir condiciones de entrada y salida

Las condiciones son Python puro: comparas valores de indicadores y precios usando los operadores habituales. La tabla siguiente muestra los patrones más comunes.

Quieres detectarCómo se escribe
Precio por encima de la EMAself.bar.close > self.ema.value
RSI en sobreventaself.rsi.value < 30
Cruce alcista precio/EMAself.data.close.crossover(self.ema.value)
Cruce bajista precio/EMAself.data.close.crossunder(self.ema.value)
Cruce alcista del MACD sobre su señalself.macd.prev < self.macd.signal and self.macd.value > self.macd.signal
Ruptura de máximos de las últimas 20 velasself.bar.close > self.data.high.highest(20)
python
def on_bar(self):
    tendencia_alcista = self.bar.close > self.ema.value
    momentum_ok = self.rsi.value < 35
    if not self.in_position and tendencia_alcista and momentum_ok:
        self.buy(sl_atr=1.5, tp_atr=3.0, risk_pct=0.01)
Combina condiciones con and / or igual que en cualquier programa Python. Aquí exigimos que se cumplan las dos antes de entrar.

Varias posiciones a la vez (avanzado)

Por defecto tu estrategia trabaja con una sola posición activa. Si quieres operar varias a la vez, establece `max_positions` en la clase y usa la propiedad `position_count` para controlarlo. Las etiquetas (`tag`) te ayudan a agruparlas y buscarlas después.

python
class MiBot(Strategy):
    max_positions = 3

    def on_bar(self):
        if self.position_count < self.max_positions and self.entrada():
            self.buy(sl_atr=1.5, tag="scalp", risk_pct=0.01)
        for p in self.get_positions_by_tag("scalp"):
            if p.pnl_pct > 0.015:
                self.close(position_id=p.id)
Abre hasta 3 posiciones en paralelo y cierra cada una en cuanto supere el 1.5 % de ganancia.

Si no indicas `lots`, `risk_pct` o `risk_usd`, la orden no sabe cuánto arriesgar y no se ejecutará. Elige siempre uno de los tres antes de hacer tu primera prueba.

Usa `self.log("...")` para dejar rastros de depuración y entender por qué tu bot entró o salió en un momento concreto cuando revises el backtest.

Para aprender a ajustar el comportamiento de tu estrategia con parámetros configurables y a revisar el historial de operaciones, continúa con el artículo «IDE: parámetros, validación e historial».