Стандартный вход на свечках. Трейлинг стоп по ленте сделок. Микроменеджмент позиций в OsEngine#10
Сегодня будем смотреть пример, в котором трейлинг стоп по позиции подтягивается по ленте сделок, а сама позиция открывается из события завершения свечи.На графике это выглядит так: 1. Открываем робот-пример. StopByTradeFeedSample.На гитХаб исходник примера находится здесь:https://github.com/AlexWan/OsEngine/blob/master/project/OsEngine/Robots/TechSamples/StopByTradeFeedSample.csВнутри проекта: 2. Конструктор и сервисный код.КОДprivate BotTabSimple _tab; private Aindicator _pc; public StrategyParameterString Regime; public StrategyParameterInt IndLength; public StrategyParameterDecimal TrailStopPercent; public StrategyParameterInt Slippage; public StrategyParameterString VolumeType; public StrategyParameterDecimal Volume; public StrategyParameterString TradeAssetInPortfolio; public StopByTradeFeedSample(string name, StartProgram startProgram) : base(name, startProgram) { TabCreate(BotTabType.Simple); _tab = TabsSimple[0]; 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); TrailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4); 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"); _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(); _tab.CandleFinishedEvent += _tab_CandleFinishedEvent; _tab.NewTickEvent += _tab_NewTickEvent; ParametrsChangeByUser += Event_ParametrsChangeByUser; Description = "An example of a robot that pulls up the stop for a position based on changes in the deals feed. IMPORTANT! Tests of this robot should be conducted on the deals feed."; }КОНЕЦ КОДАВ картинке:Поле для хранения источника BotTabSimple. В это поле потом мы положим объект источника и сможем обращаться к нему из любой части робота. Так удобнее.Поле для хранения индикатора.Параметры. Чуть позже поговорим про каждый.Создание источника BotTabSimple.Создание параметров.Создание индикатора PriceChannel. Установка его длины и отклонения из параметров.Подписка на событие CandleFinishedEvent (завершение свечи). В обработчике этого события логика открытия позиции.Подписка на событие NewTickEvent (новый трейд в ленте сделок). В обработчике этого события будет подтягивание стопа.Подписка на событие изменение параметров. В этом обработчике мы будем устанавливать индикатору новое значение длины. 3. Настройки и параметры.Создание параметров происходит в конструкторе робота:КОД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); TrailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4); 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");КОНЕЦ КОДАВ окне параметров это выглядит так:За что отвечают параметры:Regime – режим работы.Off – Выключен.On – включено без ограничений.OnlyLong – открытие только длинных позиций.OnlyShort – открытие только коротких позиций.OnlyClosePosition – доступно только закрытие позиций.Slippage in price step – проскальзывание для открытия и закрытия позиций в шагах цены.Price channel length – длина индикатора PriceChannel.Trail stop percent – величина трейлинг стопа для позиций в процентах.Volume type – режим выбора объёма.Contracts – кол-во контрактов инструмента.Contract currency – валюта контракта.Deposit percent – процент от депозита.Volume – значение объёма. Что именно, зависит от предыдущего пункта. В случае Contracts тут указывается объём инструмента. В случае Contract currency здесь указывается кол-во рублей или долларов, которыми нужно войти. В случае с Deposit percent здесь указывается % от общего депозита, которым нужно войти в контракт.Asset in portfolio – тут нужно указывать название валюты, которое будет использовано для расчёта объёма

Сегодня будем смотреть пример, в котором трейлинг стоп по позиции подтягивается по ленте сделок, а сама позиция открывается из события завершения свечи.
На графике это выглядит так:
1. Открываем робот-пример. StopByTradeFeedSample.
На гитХаб исходник примера находится здесь:
Внутри проекта:
2. Конструктор и сервисный код.
КОД
private BotTabSimple _tab; private Aindicator _pc; public StrategyParameterString Regime; public StrategyParameterInt IndLength; public StrategyParameterDecimal TrailStopPercent; public StrategyParameterInt Slippage; public StrategyParameterString VolumeType; public StrategyParameterDecimal Volume; public StrategyParameterString TradeAssetInPortfolio; public StopByTradeFeedSample(string name, StartProgram startProgram) : base(name, startProgram) { TabCreate(BotTabType.Simple); _tab = TabsSimple[0]; 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); TrailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4); 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"); _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(); _tab.CandleFinishedEvent += _tab_CandleFinishedEvent; _tab.NewTickEvent += _tab_NewTickEvent; ParametrsChangeByUser += Event_ParametrsChangeByUser; Description = "An example of a robot that pulls up the stop for a position based on changes in the deals feed. IMPORTANT! Tests of this robot should be conducted on the deals feed."; }
КОНЕЦ КОДА
В картинке:
- Поле для хранения источника BotTabSimple. В это поле потом мы положим объект источника и сможем обращаться к нему из любой части робота. Так удобнее.
- Поле для хранения индикатора.
- Параметры. Чуть позже поговорим про каждый.
- Создание источника BotTabSimple.
- Создание параметров.
- Создание индикатора PriceChannel. Установка его длины и отклонения из параметров.
- Подписка на событие CandleFinishedEvent (завершение свечи). В обработчике этого события логика открытия позиции.
- Подписка на событие NewTickEvent (новый трейд в ленте сделок). В обработчике этого события будет подтягивание стопа.
- Подписка на событие изменение параметров. В этом обработчике мы будем устанавливать индикатору новое значение длины.
3. Настройки и параметры.
Создание параметров происходит в конструкторе робота:
КОД
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); TrailStopPercent = CreateParameter("Trail stop percent", 0.2m, 0.5m, 5, 4); 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");
КОНЕЦ КОДА
В окне параметров это выглядит так:
За что отвечают параметры:
- Regime – режим работы.
- Off – Выключен.
- On – включено без ограничений.
- OnlyLong – открытие только длинных позиций.
- OnlyShort – открытие только коротких позиций.
- OnlyClosePosition – доступно только закрытие позиций.
- Slippage in price step – проскальзывание для открытия и закрытия позиций в шагах цены.
- Price channel length – длина индикатора PriceChannel.
- Trail stop percent – величина трейлинг стопа для позиций в процентах.
- Volume type – режим выбора объёма.
- Contracts – кол-во контрактов инструмента.
- Contract currency – валюта контракта.
- Deposit percent – процент от депозита.
- Volume – значение объёма. Что именно, зависит от предыдущего пункта. В случае Contracts тут указывается объём инструмента. В случае Contract currency здесь указывается кол-во рублей или долларов, которыми нужно войти. В случае с Deposit percent здесь указывается % от общего депозита, которым нужно войти в контракт.
- Asset in portfolio – тут нужно указывать название валюты, которое будет использовано для расчёта объёма, если Вы выбрали тип объёма “Deposit percent”. В тестере оставляем «Prime». На крипте это обычно “USDT”.
4. Вход в логику в событии завершения свечи. Открытие позиции.
КОД
private void _tab_CandleFinishedEvent(Listcandles) { 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 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); } } } }
КОНЕЦ КОДА
- Если параметр Regime в положении Off, выходим из метода.
- Если данные по индикатору не начали формироваться, выходим из метода.
- Если кол-во данных в индикаторе меньше, чем длинна, указанная для его расчёта, выходим из метода.
- Если параметр Regime в положении OnlyClosePosition, выходим из метода.
- Запрашиваем текущие открытые позиции.
- Заходим в логику открытия позиции, только если позиций нет.
- Запрашиваем переменные, нужные для дальнейших расчётов.
- Входим в позицию лонг, если цена пробила ценовой канал вверх.
- Входим в позицию шорт, если цена пробила ценовой канал вниз.
5. Событие появления новой сделки в ленте сделок. Выставление стопа.
КОД
private void _tab_NewTickEvent(Trade trade) { if (Regime.ValueString == "Off") { return; } ListopenPositions = _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); }
КОНЕЦ КОДА
- Если параметр Regime в положении Off, выходим из метода.
- Запрашиваем текущие открытые позиции.
- Если открытых позиций нет, выходим из метода.
- Берём открытую позицию из массива всех открытых позиций.
- Если статус позиции не равен Open, т.е. она ещё не до конца открыта или уже закрывается, ничего не делаем.
- Создаём переменные для стоп уровня и цены выставления ордера.
- Рассчитываем цену стопа и ордера для него для позиции типа BUY (лонг).
- Рассчитываем цену стопа и ордера для него для позиции типа SELL (шорт).
- Вызываем у источника метод для перевыставления трейлинг стопа.
Удачных алгоритмов!
Комментарии открыты для друзей!
OsEngine: https://github.com/AlexWan/OsEngine
Поддержка OsEngine: https://t.me/osengine_official_support
Регистрируйся в АЛОР и получай бонусы: https://www.alorbroker.ru/open
Сайт АЛОР БРОКЕР: https://www.alorbroker.ru
Раздел «Для клиентов»: https://www.alorbroker.ru/openinfo/for-clients
Программа лояльности от АЛОР БРОКЕР и OsEngine: https://smart-lab.ru/company/os_engine/blog/972745.php