Estrategia OKX MA Crossover
Esta estrategia opera un cruce de media móvil simple. Se abre una posición larga cuando el mínimo de la vela cae por debajo del valor anterior de la MA. Se abre una posición corta cuando el máximo de la vela sube por encima del valor anterior de la MA. El take profit y el stop loss se aplican como porcentajes desde el precio de entrada. La operativa comienza solo después de la fecha de inicio especificada.
Parámetros
- Tipo de vela
- Longitud de la MA
- Take Profit %
- Stop Loss %
- Fecha de inicio
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class OkxMaCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public OkxMaCrossoverStrategy()
{
_fastLength = Param(nameof(FastLength), 50).SetGreaterThanZero();
_slowLength = Param(nameof(SlowLength), 200).SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new SimpleMovingAverage { Length = FastLength };
var slow = new SimpleMovingAverage { Length = SlowLength };
var prevF = 0m;
var prevS = 0m;
var init = false;
var lastSignal = DateTimeOffset.MinValue;
var cooldown = TimeSpan.FromMinutes(600);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, f, s) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!fast.IsFormed || !slow.IsFormed)
return;
if (!init)
{
prevF = f;
prevS = s;
init = true;
return;
}
if (candle.OpenTime - lastSignal >= cooldown)
{
if (prevF <= prevS && f > s && Position <= 0)
{
BuyMarket();
lastSignal = candle.OpenTime;
}
else if (prevF >= prevS && f < s && Position >= 0)
{
SellMarket();
lastSignal = candle.OpenTime;
}
}
prevF = f;
prevS = s;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class okx_ma_crossover_strategy(Strategy):
def __init__(self):
super(okx_ma_crossover_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 50) \
.SetGreaterThanZero()
self._slow_length = self.Param("SlowLength", 200) \
.SetGreaterThanZero()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(okx_ma_crossover_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
def OnStarted2(self, time):
super(okx_ma_crossover_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
self._fast = SimpleMovingAverage()
self._fast.Length = self._fast_length.Value
self._slow = SimpleMovingAverage()
self._slow.Length = self._slow_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast, self._slow, self.OnProcess).Start()
def OnProcess(self, candle, f, s):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed:
return
fv = float(f)
sv = float(s)
if not self._initialized:
self._prev_fast = fv
self._prev_slow = sv
self._initialized = True
return
cooldown_ticks = TimeSpan.FromMinutes(600).Ticks
current_ticks = candle.OpenTime.Ticks
if current_ticks - self._last_signal_ticks >= cooldown_ticks:
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
self._last_signal_ticks = current_ticks
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._last_signal_ticks = current_ticks
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return okx_ma_crossover_strategy()