VR Smart Grid Lite переносит логику одноимённого советника MetaTrader в инфраструктуру StockSharp. Стратегия строит усредняющую сетку рыночных ордеров: стартовый объём задаётся пользователем, а при движении цены против позиции на заданное число пунктов объём каждой новой сделки удваивается. Для выхода предусмотрены два режима — полное закрытие крайних ордеров по взвешенной цене или частичное закрытие для постепенного разгрузки сетки.
Параметры
Take Profit (pips) – расстояние для фиксации прибыли, когда открыт только один ордер.
Start Volume – стартовый объём первой сделки в каждом направлении.
Maximal Volume – ограничение на максимальный объём одного ордера.
Close Mode – режим закрытия: Average закрывает самый старый и самый новый ордера по общей цели, PartClose уменьшает объём последнего ордера на стартовый объём и полностью закрывает первый ордер.
Order Step (pips) – минимальное движение против позиции, после которого разрешается ставить новый ордер.
Minimal Profit (pips) – дополнительная надбавка к взвешенной цене закрытия.
Slippage (pips) – параметр, сохранённый из оригинального советника для полноты настроек.
Candle Type – тип свечей, по которым синхронизируется работа стратегии; направление предыдущей закрытой свечи задаёт торговое смещение.
Алгоритм работы
После получения каждой завершённой свечи оценивается направление предыдущей свечи.
Если предыдущая свеча бычья и нет открытых покупок (или цена ушла ниже минимальной покупки на требуемый шаг), выставляется новый рыночный ордер на покупку.
Если предыдущая свеча медвежья и нет открытых продаж (или цена поднялась выше максимальной продажи на требуемый шаг), выставляется новый рыночный ордер на продажу.
Объём новой сделки равен стартовому объёму при первом входе и удваивается от объёма самого «дешёвого» ордера при последующих входах, с учётом максимального объёма и шага объёма инструмента.
Когда остаётся один ордер, используется простое расстояние Take Profit для выхода.
При наличии нескольких ордеров рассчитываются взвешенные уровни по крайним позициям:
В режиме Average при достижении цели закрываются оба крайних ордера, что фиксирует усреднённую прибыль.
В режиме PartClose частично закрывается объём последнего ордера (на величину стартового объёма) и полностью закрывается первый ордер, сохраняя сетку активной.
Стратегия отслеживает все открытые и закрытые ордера, чтобы внутреннее состояние сетки соответствовало реальному портфелю.
Особенности и рекомендации
Стратегия использует рыночные ордера, поэтому фактическое проскальзывание зависит от ликвидности.
Убедитесь, что минимальный объём и шаг объёма инструмента совместимы со стартовым объёмом.
Сеточные и мартина́льные подходы подразумевают быстрое наращивание риска при сильных трендах. Настоятельно рекомендуется контролировать объём позиций и устанавливать ограничения по капиталу.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// VR Smart Grid Lite: grid trading based on price levels with SMA filter.
/// </summary>
public class VrSmartGridLiteStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _gridPercent;
private readonly StrategyParam<int> _smaPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal GridPercent
{
get => _gridPercent.Value;
set => _gridPercent.Value = value;
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public VrSmartGridLiteStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_gridPercent = Param(nameof(GridPercent), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Grid %", "Grid step percentage", "Grid");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period for trend", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
decimal? lastTradePrice = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, (candle, smaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (!lastTradePrice.HasValue)
{
lastTradePrice = close;
return;
}
var step = lastTradePrice.Value * GridPercent / 100m;
if (close <= lastTradePrice.Value - step)
{
BuyMarket();
lastTradePrice = close;
}
else if (close >= lastTradePrice.Value + step)
{
SellMarket();
lastTradePrice = close;
}
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
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 vr_smart_grid_lite_strategy(Strategy):
def __init__(self):
super(vr_smart_grid_lite_strategy, self).__init__()
self._grid_percent = self.Param("GridPercent", 3.0) \
.SetDisplay("Grid %", "Grid step percentage", "Grid")
self._sma_period = self.Param("SmaPeriod", 20) \
.SetDisplay("SMA Period", "SMA period for trend", "Indicators")
self._sma = None
self._last_trade_price = None
@property
def grid_percent(self):
return self._grid_percent.Value
@property
def sma_period(self):
return self._sma_period.Value
def OnReseted(self):
super(vr_smart_grid_lite_strategy, self).OnReseted()
self._sma = None
self._last_trade_price = None
def OnStarted2(self, time):
super(vr_smart_grid_lite_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = self.sma_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._sma, self._process_candle)
subscription.Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed:
return
close = float(candle.ClosePrice)
if self._last_trade_price is None:
self._last_trade_price = close
return
step = self._last_trade_price * self.grid_percent / 100.0
if close <= self._last_trade_price - step:
self.BuyMarket()
self._last_trade_price = close
elif close >= self._last_trade_price + step:
self.SellMarket()
self._last_trade_price = close
def CreateClone(self):
return vr_smart_grid_lite_strategy()