### Implement Trading Logic with BotTabScreener Source: https://context7.com/alexwan/osengine/llms.txt This example demonstrates how to use BotTabScreener to manage trading across multiple instruments. It subscribes to new tab creation events and attaches trading logic, including indicator creation and order execution, to each new instrument's tab. ```csharp [Bot("ScreenerBot")] public class ScreenerBot : BotPanel { private BotTabScreener _screener; private StrategyParameterDecimal _volume; private StrategyParameterInt _smaPeriod; public ScreenerBot(string name, StartProgram startProgram) : base(name, startProgram) { TabCreate(BotTabType.Screener); _screener = TabsScreener[0]; _volume = CreateParameter("Объём", 1m, 0.1m, 5m, 0.1m); _smaPeriod = CreateParameter("Период SMA", 50, 5, 300, 1); // Подписка на событие создания новой дочерней вкладки (новый инструмент) _screener.NewTabCreateEvent += OnNewTabCreated; // Уже существующие вкладки при перезапуске робота for (int i = 0; i < _screener.Tabs.Count; i++) SubscribeToTab(_screener.Tabs[i]); } private void OnNewTabCreated(BotTabSimple tab) { SubscribeToTab(tab); } private void SubscribeToTab(BotTabSimple tab) { // Добавить индикатор на каждую вкладку скринера Aindicator sma = IndicatorsFactory.CreateIndicatorByName("Sma", tab.TabName + "Sma", false); sma = (Aindicator)tab.CreateCandleIndicator(sma, "Prime"); sma.ParametersDigit[0].Value = _smaPeriod.ValueInt; sma.Save(); tab.CandleFinishedEvent += candles => OnCandleFinished(tab, sma, candles); } private void OnCandleFinished(BotTabSimple tab, Aindicator sma, List candles) { if (candles.Count < _smaPeriod.ValueInt + 5) return; if (sma.DataSeries[0].Values == null) return; decimal close = candles[candles.Count - 1].Close; decimal lastSma = sma.DataSeries[0].Last; List pos = tab.PositionsOpenAll; if (pos.Count == 0 && close > lastSma) tab.BuyAtMarket(_volume.ValueDecimal); else if (pos.Count > 0 && close < lastSma) tab.CloseAtMarket(pos[0], pos[0].OpenVolume); } public override string GetNameStrategyType() => "ScreenerBot"; public override void ShowIndividualSettingsDialog() { } } ``` -------------------------------- ### Subscribe to BotTabSimple Market Events Source: https://context7.com/alexwan/osengine/llms.txt This example shows how to subscribe to various market events provided by BotTabSimple, such as candle finishes, updates, new ticks, and position changes. It's useful for implementing trading logic based on real-time market data and position status. ```csharp public class EventsExample : BotPanel { private BotTabSimple _tab; public EventsExample(string name, StartProgram startProgram) : base(name, startProgram) { TabCreate(BotTabType.Simple); _tab = TabsSimple[0]; // Свеча закрылась (основное событие для торговой логики) _tab.CandleFinishedEvent += candles => { Candle last = candles[candles.Count - 1]; // Торговая логика по закрытому бару }; // Обновление формирующейся свечи (несколько раз в секунду) _tab.CandleUpdateEvent += candles => { /* Scalping / HFT логика */ }; // Новый тик _tab.NewTickEvent += trade = { decimal price = trade.Price; decimal vol = trade.Volume; Side side = trade.Side; // Buy или Sell }; // Позиция успешно открыта _tab.PositionOpeningSuccesEvent += pos = { SendNewLogMessage($"Позиция открыта: {pos.Direction} {pos.OpenVolume} @ {pos.EntryPrice}", Logging.LogMessageType.Trade); // Сразу выставить стоп и тейк decimal stop = pos.EntryPrice * (pos.Direction == Side.Buy ? 0.98m : 1.02m); decimal profit = pos.EntryPrice * (pos.Direction == Side.Buy ? 1.03m : 0.97m); _tab.CloseAtStopMarket(pos, stop); _tab.CloseAtProfitMarket(pos, profit); }; // Позиция закрыта _tab.PositionClosingSuccesEvent += pos = { decimal pnl = pos.ProfitOperationPersent; SendNewLogMessage($"Позиция закрыта. PnL: {pnl:F2}%", Logging.LogMessageType.Trade); }; // Сработал стоп-ордер на позиции _tab.PositionStopActivateEvent += pos => { /* обработка стопа */ }; // Сработал профит-ордер _tab.PositionProfitActivateEvent += pos => { /* обработка профита */ }; // Изменился портфель _tab.PortfolioOnExchangeChangedEvent += portfolio = { decimal equity = portfolio.ValueCurrent; }; } public override string GetNameStrategyType() => "EventsExample"; public override void ShowIndividualSettingsDialog() { } } ``` -------------------------------- ### Analyze Position Object Properties Source: https://context7.com/alexwan/osengine/llms.txt Accesses and analyzes various properties of the Position object, such as direction, state, volume, entry price, PnL, orders, trades, and signals. Includes an example of closing a position based on PnL. ```csharp private void AnalyzePosition(Position pos) { // Основные поля Side direction = pos.Direction; // Side.Buy или Side.Sell PositionStateType state = pos.State; // Opening, Open, Closing, Done и т.д. decimal openVolume = pos.OpenVolume; // текущий открытый объём decimal entryPrice = pos.EntryPrice; // средняя цена входа decimal pnlPercent = pos.ProfitOperationPersent; // PnL в % // Ордера List openOrders = pos.OpenOrders; // ордера на открытие List closeOrders = pos.CloseOrders; // ордера на закрытие // Мои сделки (исполненные трейды) List myTrades = pos.MyTrades; // Метки сигналов string signalOpen = pos.SignalTypeOpen; string signalClose = pos.SignalTypeClose; string signalStop = pos.SignalTypeStop; // Стоп и профит активны? bool stopActive = pos.StopOrderIsActive; bool profitActive = pos.ProfitOrderIsActive; // Пример: если PnL > 2% — закрыть по рынку if (pnlPercent > 2m) _tab.CloseAtMarket(pos, openVolume, "TakeProfit_2pct"); } ``` -------------------------------- ### Create Strategy Parameters with BotPanel Source: https://context7.com/alexwan/osengine/llms.txt Defines various types of strategy parameters that are saved to disk, displayed in the GUI, and iterated by the optimizer. Parameters can be grouped by GUI tabs using the 'tabControlName' argument. ```csharp public class ParametersExample : BotPanel { public ParametersExample(string name, StartProgram startProgram) : base(name, startProgram) { // Decimal: имя, значение по умолчанию, min, max, шаг[, вкладка GUI] StrategyParameterDecimal pDec = CreateParameter("Объём", 1.5m, 0.1m, 10m, 0.1m, "Base"); // Int StrategyParameterInt pInt = CreateParameter("Период", 50, 5, 300, 1, "Индикаторы"); // String (выпадающий список) StrategyParameterString pStr = CreateParameter("Режим", "Off", new[] { "Off", "On", "OnlyLong", "OnlyShort", "OnlyClosePosition" }, "Base"); // Bool (чекбокс) StrategyParameterBool pBool = CreateParameter("Фильтр SMA", false, "Фильтры"); // Время суток (для ограничения торгового окна) StrategyParameterTimeOfDay pTimeStart = CreateParameterTimeOfDay("Начало торгов", 10, 0, 0, 0, "Base"); StrategyParameterTimeOfDay pTimeEnd = CreateParameterTimeOfDay("Конец торгов", 23, 0, 0, 0, "Base"); // Кнопка в GUI StrategyParameterButton btn = CreateParameterButton("Сбросить позиции", "Base"); btn.UserClickOnButtonEvent += () => SendNewLogMessage("Кнопка нажата", Logging.LogMessageType.System); // Decimal+CheckBox StrategyParameterDecimalCheckBox pDCB = CreateParameterDecimalCheckBox( "Стоп-лосс %", 2m, 0.1m, 10m, 0.1m, false, "Risk"); // Использование значений параметров в логике TabCreate(BotTabType.Simple); BotTabSimple tab = TabsSimple[0]; tab.CandleFinishedEvent += candles => { if (pStr.ValueString == "Off") return; DateTime now = tab.TimeServerCurrent; if (now.TimeOfDay < pTimeStart.Value.TimeOfDay) return; if (now.TimeOfDay > pTimeEnd.Value.TimeOfDay) return; if (pBool.ValueBool) { // Логика с включённым фильтром } decimal volume = pDec.ValueDecimal; // ... торговая логика }; } public override string GetNameStrategyType() => "ParametersExample"; public override void ShowIndividualSettingsDialog() { } } ``` -------------------------------- ### Execute Limit Orders with BuyAtLimit/SellAtLimit Source: https://context7.com/alexwan/osengine/llms.txt Utilize limit orders for precise entry prices. These are useful for entering positions at a specific price point, potentially better than the current market price. ```csharp private void OnCandleFinished(List candles) { if (candles.Count < 10) return; decimal close = candles[candles.Count - 1].Close; decimal slippage = _tab.Security.PriceStep * 2; // 2 шага цены List pos = _tab.PositionsOpenAll; if (pos.Count == 0) { // Покупаем чуть выше последней цены Position openPos = _tab.BuyAtLimit(1m, close + slippage); // Продаём чуть ниже // Position openPos = _tab.SellAtLimit(1m, close - slippage, "MySignal"); } else { // Добавляем объём к существующей Long-позиции (усреднение) if (pos[0].Direction == Side.Buy) _tab.BuyAtLimitToPosition(pos[0], close - slippage, 0.5m); } } ``` -------------------------------- ### MyTrendBot: C# Trading Robot Implementation Source: https://context7.com/alexwan/osengine/llms.txt This C# code defines a trading robot that inherits from BotPanel. It demonstrates how to declare strategy parameters, create indicators like SMA, subscribe to events, and implement basic trading logic based on price and indicator crossovers. Use this as a template for creating custom trading strategies. ```csharp using OsEngine.Entity; using OsEngine.Indicators; using OsEngine.OsTrader.Panels; using OsEngine.OsTrader.Panels.Attributes; using OsEngine.OsTrader.Panels.Tab; using System.Collections.Generic; [Bot("MyTrendBot")] public class MyTrendBot : BotPanel { private BotTabSimple _tab; // Параметры стратегии — отображаются в GUI автоматически private StrategyParameterString _regime; private StrategyParameterDecimal _volume; private StrategyParameterInt _smaPeriod; private StrategyParameterDecimal _slippage; // Индикаторы private Aindicator _sma; public MyTrendBot(string name, StartProgram startProgram) : base(name, startProgram) { // Создать вкладку простой торговли (один инструмент) TabCreate(BotTabType.Simple); _tab = TabsSimple[0]; // Объявить параметры (name, defaultValue, min, max, step[, tabGroup]) _regime = CreateParameter("Режим", "Off", new[] { "Off", "On", "OnlyLong", "OnlyShort" }, "Base"); _volume = CreateParameter("Объём", 1m, 0.1m, 10m, 0.1m, "Base"); _smaPeriod = CreateParameter("Период SMA", 50, 10, 300, 1, "Индикаторы"); _slippage = CreateParameter("Проскальз. %", 0m, 0, 2, 0.1m, "Base"); // Создать индикатор SMA и добавить на основной ценовой чарт _sma = IndicatorsFactory.CreateIndicatorByName("Sma", name + "Sma", false); _sma = (Aindicator)_tab.CreateCandleIndicator(_sma, "Prime"); _sma.ParametersDigit[0].Value = _smaPeriod.ValueInt; _sma.Save(); // Подписаться на события _tab.CandleFinishedEvent += OnCandleFinished; ParametrsChangeByUser += OnParamsChanged; } public override string GetNameStrategyType() => "MyTrendBot"; public override void ShowIndividualSettingsDialog() { } private void OnParamsChanged() { if (_sma.ParametersDigit[0].Value != _smaPeriod.ValueInt) { _sma.ParametersDigit[0].Value = _smaPeriod.ValueInt; _sma.Reload(); _sma.Save(); } } private void OnCandleFinished(List candles) { if (_regime.ValueString == "Off") return; if (candles.Count < _smaPeriod.ValueInt + 5) return; decimal lastClose = candles[candles.Count - 1].Close; decimal lastSma = _sma.DataSeries[0].Last; List positions = _tab.PositionsOpenAll; if (positions.Count == 0) { if (lastClose > lastSma && _regime.ValueString != "OnlyShort") _tab.BuyAtMarket(_volume.ValueDecimal); else if (lastClose < lastSma && _regime.ValueString != "OnlyLong") _tab.SellAtMarket(_volume.ValueDecimal); } else { // Закрыть позицию при пересечении SMA в обратную сторону Position pos = positions[0]; if (pos.Direction == Side.Buy && lastClose < lastSma) _tab.CloseAtMarket(pos, pos.OpenVolume); else if (pos.Direction == Side.Sell && lastClose > lastSma) _tab.CloseAtMarket(pos, pos.OpenVolume); } } } ``` -------------------------------- ### Create and Use Technical Indicators Source: https://context7.com/alexwan/osengine/llms.txt Demonstrates three methods for creating technical indicators (SMA, ATR, Bollinger Bands) using the OS Engine platform's API. The indicators can then be used within trading logic to make decisions. ```csharp // В конструкторе BotPanel: // Способ 1: IndicatorsFactory + CreateCandleIndicator (классический) Aindicator sma = IndicatorsFactory.CreateIndicatorByName("Sma", name + "Sma", false); sma = (Aindicator)_tab.CreateCandleIndicator(sma, "Prime"); // "Prime" = основная панель sma.ParametersDigit[0].Value = 50; // период sma.Save(); // Способ 2: CreateIndicator (обобщённый) // Aindicator bollinger = _tab.CreateIndicator(new Bollinger(), "Prime"); // Способ 3: через BotTabSimple.CreateIndicator(bot, typeName, area, params) Aindicator atr = _tab.CreateIndicator(this, "ATR", "NewArea0", 14m); // В торговой логике: private void OnCandleFinished(List candles) { if (_sma.DataSeries[0].Values == null) return; decimal lastSma = _sma.DataSeries[0].Last; decimal prevSma = _sma.DataSeries[0].Values[_sma.DataSeries[0].Values.Count - 2]; // Пример: Bollinger Bands (3 серии данных: Up, Mid, Down) // decimal upBB = _bollinger.DataSeries[0].Last; // decimal midBB = _bollinger.DataSeries[1].Last; // decimal downBB = _bollinger.DataSeries[2].Last; bool smaGrowth = lastSma > prevSma; decimal close = candles[candles.Count - 1].Close; if (close > lastSma && smaGrowth) _tab.BuyAtMarket(1m); else if (close < lastSma && !smaGrowth) _tab.SellAtMarket(1m); } ``` -------------------------------- ### Execute Stop Orders with BuyAtStop/SellAtStop Source: https://context7.com/alexwan/osengine/llms.txt Employ stop orders to trigger entry orders once a specific price level is reached. These are conditional orders that become market or limit orders when activated. ```csharp private void OnCandleFinished(List candles) { if (candles.Count < 20) return; decimal high = candles[candles.Count - 1].High; decimal low = candles[candles.Count - 1].Low; // Вход в Long при пробое максимума свечи вверх // Параметры: объём, цена ордера, цена активации, тип активации, срок жизни (баров) _tab.BuyAtStop( volume: 1m, priceLimit: high + _tab.Security.PriceStep * 5, priceRedLine: high, activateType: StopActivateType.HigherOrEqual, expiresBars: 2, signalType: "BreakHigh" ); // Вход в Short при пробое минимума вниз _tab.SellAtStop( volume: 1m, priceLimit: low - _tab.Security.PriceStep * 5, priceRedLine: low, activateType: StopActivateType.LowerOrEqualThis, expiresBars: 2 ); // Отмена всех pending стоп-ордеров на открытие // _tab.BuyAtStopCancel(); // _tab.SellAtStopCancel(); } ```