Esta estrategia replica el experto de MetaTrader "Exp_SilverTrend_CrazyChart" usando la API de alto nivel de StockSharp. Opera en ambos lados del mercado comparando dos buffers del indicador personalizado SilverTrend CrazyChart. Cuando la banda retrasada cruza la banda actual, abre una posición en la dirección de la banda dominante y cierra cualquier exposición opuesta.
Detalles
Criterios de entrada:
Largo: La barra de señal finalizada anterior muestra la banda actual por encima de la banda retrasada, y en la barra evaluada la banda actual cae por debajo o toca la banda retrasada. Las entradas largas pueden deshabilitarse con AllowBuyEntry.
Corto: La barra de señal finalizada anterior muestra la banda actual por debajo de la banda retrasada, y en la barra evaluada la banda actual sube por encima o toca la banda retrasada. Las entradas cortas pueden deshabilitarse con AllowSellEntry.
Largo/Corto: Ambas direcciones.
Criterios de salida:
Las posiciones largas se cierran cuando la banda retrasada supera a la banda actual (AllowBuyExit) o cuando se activan los límites de stop-loss/take-profit.
Las posiciones cortas se cierran cuando la banda actual supera a la banda retrasada (AllowSellExit) o cuando se activan los límites de stop-loss/take-profit.
Stops: Utiliza desplazamientos de precio absolutos especificados por StopLossPoints y TakeProfitPoints. Si cualquiera de los valores es cero, ese límite se ignora.
Filtros:
SignalBar selecciona cuántas velas completadas hacia atrás se evalúa la lógica de cruce.
CandleType controla el marco temporal utilizado para todos los cálculos.
Parámetros
CandleType – Serie de velas usada para el indicador (predeterminado: velas de 1 hora).
Length – Período de oscilación (SSP) pasado al indicador SilverTrend CrazyChart.
KMin – Coeficiente de canal inferior que controla la distancia de la banda retrasada.
KMax – Coeficiente de canal superior que controla la distancia de la banda actual.
SignalBar – Número de velas completadas hacia atrás usadas para evaluar el cruce (equivalente al SignalBar original).
AllowBuyExit / AllowSellExit – Activar/desactivar el cierre de posiciones largas/cortas existentes.
StopLossPoints – Distancia absoluta de precio desde la entrada para el stop-loss largo y el take-profit corto.
TakeProfitPoints – Distancia absoluta de precio desde la entrada para el take-profit largo y el stop-loss corto.
Volume – Volumen de estrategia heredado que define el tamaño base de la orden.
Lógica del indicador
El SilverTrendCrazyChartIndicator incluido reproduce los buffers MQL originales:
Length, KMin y KMax calculan un canal de oscilación desde el máximo más alto y el mínimo más bajo sobre la ventana de retrospectiva.
La banda "actual" corresponde al buffer 0 en MetaTrader y reacciona inmediatamente a la última barra.
La banda "retrasada" es el buffer 1, que desplaza la banda actual Length + 1 barras para coincidir con la lógica de dibujo original.
Se activa una compra cuando la banda retrasada, actuando como filtro de tendencia, cruza por encima de la banda actual, mientras que una venta aparece cuando la relación se invierte. El parámetro SignalBar garantiza que solo las velas completadas participen en la decisión, igualando el comportamiento del experto original.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// SilverTrend CrazyChart strategy (simplified).
/// Uses Highest/Lowest channel inversions for entries.
/// </summary>
public class SilverTrendCrazyChartStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _length;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
public SilverTrendCrazyChartStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_length = Param(nameof(Length), 14)
.SetGreaterThanZero()
.SetDisplay("Length", "Channel length", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = Length };
var lowest = new Lowest { Length = Length };
decimal prevHigh = 0, prevLow = 0;
bool hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, (ICandleMessage candle, decimal highValue, decimal lowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevHigh = highValue;
prevLow = lowValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevHigh = highValue;
prevLow = lowValue;
return;
}
var close = candle.ClosePrice;
var mid = (highValue + lowValue) / 2m;
var prevMid = (prevHigh + prevLow) / 2m;
// Price crosses above channel midpoint
if (close > mid && candle.OpenPrice <= prevMid && Position <= 0)
{
BuyMarket();
}
// Price crosses below channel midpoint
else if (close < mid && candle.OpenPrice >= prevMid && Position >= 0)
{
SellMarket();
}
prevHigh = highValue;
prevLow = lowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class silver_trend_crazy_chart_strategy(Strategy):
def __init__(self):
super(silver_trend_crazy_chart_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._length = self.Param("Length", 14) \
.SetDisplay("Length", "Channel length", "Indicators")
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def Length(self):
return self._length.Value
def OnReseted(self):
super(silver_trend_crazy_chart_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(silver_trend_crazy_chart_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
highest = Highest()
highest.Length = self.Length
lowest = Lowest()
lowest.Length = self.Length
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if not self._has_prev:
self._prev_high = hv
self._prev_low = lv
self._has_prev = True
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
mid = (hv + lv) / 2.0
prev_mid = (self._prev_high + self._prev_low) / 2.0
if close > mid and open_p <= prev_mid and self.Position <= 0:
self.BuyMarket()
elif close < mid and open_p >= prev_mid and self.Position >= 0:
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return silver_trend_crazy_chart_strategy()