
Сегодня будем смотреть пример, в котором трейлинг стоп по позиции подтягивается по ленте сделок, а сама позиция открывается из события завершения свечи.
На графике это выглядит так:
На гитХаб исходник примера находится здесь:
Внутри проекта:

2. Конструктор и сервисный код.
КОД
private BotTabSimple _tab;
// Basic settings
private StrategyParameterString _regime;
private StrategyParameterInt _<a class="dictionary_link" href="/finansoviy-slovar/slippage/">slippage</a>;
// GetVolume settings
private StrategyParameterString _volumeType;
private StrategyParameterDecimal _volume;
private StrategyParameterString _tradeAssetInPortfolio;
// Indicator setting
private StrategyParameterInt _indLength;
// Indicator
private Aindicator _pc;
// Exit setting
private StrategyParameterDecimal _trailStopPercent;
public StopByTradeFeedSample(string name, StartProgram startProgram) : base(name, startProgram)
{
TabCreate(BotTabType.Simple);
_tab = TabsSimple[0];
// Basic settings
_regime = CreateParameter("Regime", "Off", new[] { "Off", "On", "OnlyLong", "OnlyShort", "OnlyClosePosition" });
_slippage = CreateParameter("Slippage in price step", 0, 0, 20, 1);
_indLength = CreateParameter("<a class="dictionary_link" href="/finansoviy-slovar/price%20channel/">Price channel</a> length", 10, 10, 80, 3);
// GetVolume settings
_volumeType = CreateParameter("Volume type", "Deposit percent", new[] { "Contracts", "Contract currency", "Deposit percent" });
_volume = CreateParameter("Volume", 10, 1.0m, 50, 4);
_tradeAssetInPortfolio = CreateParameter("Asset in portfolio", "Prime");
// Exit setting
_trailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4);
// Create indicator PriceChannel
_pc = IndicatorsFactory.CreateIndicatorByName("PriceChannel", name + "PriceChannel", false);
_pc = (Aindicator)_tab.CreateCandleIndicator(_pc, "Prime");
_pc.ParametersDigit[0].Value = _indLength.ValueInt;
_pc.ParametersDigit[1].Value = _indLength.ValueInt;
_pc.Save();
// Subscribe to the candle finished event
_tab.CandleFinishedEvent += _tab_CandleFinishedEvent;
// Subscribe to the new tick event
_tab.NewTickEvent += _tab_NewTickEvent;
// Subscribe to the indicator update event
ParametrsChangeByUser += Event_ParametrsChangeByUser;
Description = OsLocalization.Description.DescriptionLabel108;
}КОНЕЦ КОДА
В картинке:
Создание параметров происходит в конструкторе робота:
КОД
// Basic settings
_regime = CreateParameter("Regime", "Off", new[] { "Off", "On", "OnlyLong", "OnlyShort", "OnlyClosePosition" });
_slippage = CreateParameter("Slippage in price step", 0, 0, 20, 1);
_indLength = CreateParameter("Price channel length", 10, 10, 80, 3);
// GetVolume settings
_volumeType = CreateParameter("Volume type", "Deposit percent", new[] { "Contracts", "Contract currency", "Deposit percent" });
_volume = CreateParameter("Volume", 10, 1.0m, 50, 4);
_tradeAssetInPortfolio = CreateParameter("Asset in portfolio", "Prime");
// Exit setting
_trailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4);КОНЕЦ КОДА
В окне параметров это выглядит так:
За что отвечают параметры:
КОД
private void _tab_CandleFinishedEvent(List<Candle> candles)
{
if (Regime.ValueString == "Off")
{
return;
}
if (_pc.DataSeries[0].Values == null
|| _pc.DataSeries[1].Values == null)
{
return;
}
if (_pc.DataSeries[0].Values.Count < _pc.ParametersDigit[0].Value + 2
|| _pc.DataSeries[1].Values.Count < _pc.ParametersDigit[1].Value + 2)
{
return;
}
if (Regime.ValueString == "OnlyClosePosition")
{
return;
}
List<Position> openPositions = _tab.PositionsOpenAll;
if (openPositions == null
|| openPositions.Count == 0)
{// no positions
decimal lastPrice = candles[candles.Count - 1].Close;
decimal lastPcUp = _pc.DataSeries[0].Values[_pc.DataSeries[0].Values.Count - 2];
decimal lastPcDown = _pc.DataSeries[1].Values[_pc.DataSeries[1].Values.Count - 2];
// long
if (Regime.ValueString != "OnlyShort")
{
if (lastPrice > lastPcUp)
{
_tab.BuyAtLimit(GetVolume(_tab), lastPrice + Slippage.ValueInt * _tab.Security.PriceStep);
}
}
// Short
if (Regime.ValueString != "OnlyLong")
{
if (lastPrice < lastPcDown)
{
_tab.SellAtLimit(GetVolume(_tab), lastPrice - Slippage.ValueInt * _tab.Security.PriceStep);
}
}
}
}КОНЕЦ КОДА
КОД
private void _tab_NewTickEvent(Trade trade)
{
if (_regime.ValueString == "Off")
{
return;
}
List<Position> openPositions = _tab.PositionsOpenAll;
if (openPositions == null
|| openPositions.Count == 0)
{
return;
}
Position myPos = openPositions[0];
if(myPos.State != PositionStateType.Open)
{
return;
}
decimal stopPrice = 0;
decimal orderPrice = 0;
if (myPos.Direction == Side.Buy)
{
stopPrice = trade.Price - (trade.Price * (_trailStopPercent.ValueDecimal/100));
orderPrice = stopPrice - _slippage.ValueInt * _tab.Security.PriceStep;
}
else if(myPos.Direction == Side.Sell)
{
stopPrice = trade.Price + (trade.Price * (_trailStopPercent.ValueDecimal / 100));
orderPrice = stopPrice + _slippage.ValueInt * _tab.Security.PriceStep;
}
_tab.CloseAtTrailingStop(myPos,stopPrice,orderPrice);
}КОНЕЦ КОДА
Удачных алгоритмов!
Комментарии открыты для друзей!
OsEngine: https://github.com/AlexWan/OsEngine
Поддержка OsEngine: https://t.me/osengine_official_support