Найти в Дзене

Новая версия доработанного Робота на основе стратегии StepByStep.

Здравствуйте дорогие подписчики и гости канала. Сегодня 1 декабря, прошло 6 месяцев, как не стало моей любимой жены. Боль утраты не затихает, мысли о ней и воспоминания постоянно со мной. Поэтому не получается пока часто писать на канале. В память о моей любимой жене я хочу предоставить вам возможность, скачать новую, доработанную и полностью протестированную на реальном счете в течении 9 месяцев, версию Робота SBS_RS_v3. Робот показал стабильную работу и доходность, которая меня полностью устраивает. Робот в настройках похож на предыдущую версию, но внесены существенные дополнения. Полное описание напишу в ближайшее время. Для корректной работы робота, индикатор необходимо обязательно установить. //===================================================== function Initialize() { IndicatorName = "str_Invest_Grid_7"; PriceStudy = true; AddInput("Input", Inputs.Candle); AddSeries("str_Invest_Grid_7", DrawAs.Line, Color.Red); // Дополнительные параметры: AddParameter("Price", 20); AddParamet
Оглавление

Здравствуйте дорогие подписчики и гости канала.

Сегодня 1 декабря, прошло 6 месяцев, как не стало моей любимой жены. Боль утраты не затихает, мысли о ней и воспоминания постоянно со мной. Поэтому не получается пока часто писать на канале.

В память о моей любимой жене я хочу предоставить вам возможность, скачать новую, доработанную и полностью протестированную на реальном счете в течении 9 месяцев, версию Робота SBS_RS_v3. Робот показал стабильную работу и доходность, которая меня полностью устраивает. Робот в настройках похож на предыдущую версию, но внесены существенные дополнения. Полное описание напишу в ближайшее время.

Индикатор к данной версии.

Для корректной работы робота, индикатор необходимо обязательно установить.

//=====================================================

function Initialize()

{

IndicatorName = "str_Invest_Grid_7";

PriceStudy = true;

AddInput("Input", Inputs.Candle);

AddSeries("str_Invest_Grid_7", DrawAs.Line, Color.Red);

// Дополнительные параметры:

AddParameter("Price", 20);

AddParameter("PL", 1);

AddParameter("Delta", 1);

AddParameter("PL1", 1);

AddParameter("Delta1", 1);

AddParameter("Type", 0);

// Серии для отображения цен

AddSeries("L1", DrawAs.Custom, Color.LightGreen, true);

AddSeries("L2", DrawAs.Custom, Color.Red, true);

AddSeries("L3", DrawAs.Custom, Color.Red, true);

AddSeries("L4", DrawAs.Custom, Color.Green, true);

AddSeries("L5", DrawAs.Custom, Color.Green, true);

// Уровни

AddLevel(0, Color.LightGreen, LineStyles.DashBig, 2, "str_Invest_Grid_7");

AddLevel(0, Color.Red, "str_Invest_Grid_7");

AddLevel(0, Color.Red, LineStyles.Dot, 2, "str_Invest_Grid_7");

AddLevel(0, Color.Green, LineStyles.Dot, 2, "str_Invest_Grid_7");

AddLevel(0, Color.Green, "str_Invest_Grid_7");

}

function Evaluate()

{

if (CurrentIndex == MaxIndex)

{

// Alfadirect.

// Индикатор для отображения в стартегии Invest_Grid

// Если Type == 0, рисуем отклонение в абсолюте

if (Type == 0)

{

Levels[0].Level = Price;

Levels[1].Level = Price - PL;

Levels[2].Level = Price - PL1;

Levels[3].Level = Price + Delta1;

Levels[4].Level = Price + Delta;

}

// Если Type == 1 рисуем отклонение в %

if (Type == 1)

{

Levels[0].Level = Price;

Levels[1].Level = Price*(1-0.01*PL);

Levels[2].Level = Price*(1-0.01*PL1);

Levels[3].Level = Price*(1+0.01*Delta1);

Levels[4].Level = Price*(1+0.01*Delta);

L1 = Levels[0].Level;

L2 = Levels[1].Level;

L3 = Levels[2].Level;

L4 = Levels[3].Level;

L5 = Levels[4].Level;

Levels[0].Color = L1.Color;

Levels[1].Color = L2.Color;

Levels[2].Color = L3.Color;

Levels[3].Color = L4.Color;

Levels[4].Color = L5.Color;

}

}

}

//===========================================================

для установки нового индикатора, нужно.

Открываем график котировок акций. На графике жмем на икоку График (смотри скриншот №1 красная стрелка).

№1. График с прорисованными уровнями для Робота.
№1. График с прорисованными уровнями для Робота.

Открывается окно, тут выбираем закладку "Пользовательские" (стрелка 1). Скриншот №2

№2 Список индикаторов.
№2 Список индикаторов.

Затем жмем кнопку "Редактор" (стрелка 2). Открывается окно Редактора. Скриншот №3.

Так как мы не создаем новый Индикатор в ручную, мы жмем на значок "Новый"указанный стрелкой

№3 Окно редактора.
№3 Окно редактора.

В открывшимся окне выделяем весь текст и вместо него вставляем текст Индикатора из статьи, Затем жмем на иконку "Компилировать" (крайняя справа). а далее жмем на иконку "Сохранить как...". (указана стрелкой). Скриншот №4

№4 Создание нового индикатора.
№4 Создание нового индикатора.

Открывается окно сохранения. Красным прямоугольником выделен путь сохранения. именно там хранятся все индикаторы и Стандартные и Пользовательские. Если вы сами создавали добавляли Индикаторы, при переносе терминала на другой компьютер, можно просто скопировать и перенести содержимое папки, и вам Индикаторы создавать снова будет не нужно.

Но мы отвлеклись. Программа сама берет название нового индикатора из текста Индикатора. Вам тут остается только нажать кнопку "Сохранить".

Новый индикатор появится у вас в списке Пользовательских Индикаторов.

№5. Сохранение нового индикатора.
№5. Сохранение нового индикатора.

Теперь при запуске Робота, и у вас на графике цены будет прорисовано 5 уровней.

№6 Уровни.
№6 Уровни.

Уровень №1 Зеленый пунктир. Этот уровень который в данный момент торгуется и соответствует цене покупки акций.

Уровень №2 Зеленые точки. Это уровень при достижении которого текущей ценой будет выставлена заявка на продажу по цене уровня №4.

Уровень №3. Красные точки. Уровень при падении текущей цены до которого, будет выставлена заявка на покупку по цене уровня №5.

Уровень №4. Сплошная зеленая линия. Уровень на который выставляется заявка на продажу.

Уровень №5. Сплошная красная линия. Уровень на котором выставляется заявка на покупку.

Для того, что бы цены уровней были подписаны цифрами как на скриншоте нужно сделать следующее. Кликаем в любом месте графика правой кнопкой мыши и выбираем в выпавшем меню пункт "Настроить"

№7. Настроить график
№7. Настроить график

В открывшимся окне выбираем пункт "Индикаторы" прямоугольник цифра №1.

№8. Настройка графика.
№8. Настройка графика.

Из списка индикаторов выбираем str_Invest_Grid_7 прямоугольник №2 и жмем 2 скобки с левой стороны перед названием. В открывшимся окне ставим птичку прямоугольник №3, Затем жмем кнопки №4 и потом №5. И у вас получатся уровни с подписанной ценой как на скриншоте. К сожалению терминал не запоминает, установленную птичку в прямоугольнике №3 и после перезагрузки терминала вам всю процедуру придется каждый раз повторять. Подписанные уровни удобны тем, что мы можем видеть в каком состоянии находится Робот относительно текущей цены инструмента.

Полный текст Робота SBS_RS_v3

//=====================================================

function Initialize()

{

StrategyName = "SBS_RS_v3";

AddInput("Input1", Inputs.Candle, 5, true, "CHMF=МБ ЦК");

AddParameter("StartQ", 6, "Стартовое кол-во", 0);

AddParameter("Q", 2, "Кол-во докупки", 0);

AddParameter("SellAboveThisLevel", 0, "Продаем только выше этой цены", 0); // если 0, продаем без ограничений

AddParameter("BuyBelowThisLevel", 1000000, "Покупаем только ниже этой цены", 0); // если 0, не покупаем

AddParameter("DeltaPercentBuy", 1.5, "% изменения цены для докупки", 0);
AddParameter("DeltaPercentBuy1", 0.7, "% изменения цены для выставление заявки докупки", 0);

AddParameter("DeltaPercentSell", 1.5, "% изменения цены для продажи", 0);
AddParameter("DeltaPercentSell1", 0.7, "% изменения цены для выставления заявки продажи", 0);
AddParameter("QSlippage", 0.3, "проскальзывание для докупки Q", 0);

AddParameter("DeltaIncBuy", 1, "на сколько увеличиваем дельту", 0);

AddParameter("DeltaIncSell", 1, "на сколько увеличиваем дельту", 0);

AddParameter("MaxLevels", 5, "Максимальное желательное количество уровней", 0);

AddParameter("MinLevels", 5, "Минимальное желательное количество уровней", 0);

AddParameter("TypeQ", 1, "Тип установки количества. Тип=1 - в штуках, Тип=2 - в валюте", 0);

AddParameter("ClosePositionAtPrice", 0, "Закрыть всю позицию, если цена выше", 0);

AddParameter("BuyOK", 1, "Покупки разрешены", 0);

AddParameter("SellOK", 1, "Продажи разрешены", 0);
AddParameter("MaxPriceParam", 0.0, "Внимание! Изменение этого параметра меняет глоальную переменную. Стратегия может работат некорректно", 0); //Разрешает изменение глобальной переменной
AddParameter("MinPriceParam", 0.0, "Внимание! Изменение этого параметра меняет глоальную переменную. Стратегия может работат некорректно", 0); // разрешает изменение глобальной переменной.
AddParameter("DohodZakr", 0.0, "% доход по закрытым роботам", 0);
AddParameter("Dividend", 0.0, "% дивиденды по акциям робота", 0);

AddGlobalVariable("inited", Types.Boolean, false);

AddGlobalVariable("lastSignalId", Types.Int, 0);

AddGlobalVariable("xPosition", Types.Double, 0.0);

AddGlobalVariable("LastPrice", Types.DoubleDictionary);

AddGlobalVariable("LastPriceCount", Types.Int, 0);

AddGlobalVariable("LongLimitStart", Types.Double, 0);

AddGlobalVariable("MaxPrice", Types.Double, 0); // максимум с начала работы робота

AddGlobalVariable("MinPrice", Types.Double, 0);

AddGlobalVariable("CurrDeltaBuy", Types.Double, 0);

AddGlobalVariable("CurrDeltaSell", Types.Double, 0);

AddGlobalVariable("SellPrice", Types.Double, 0);

AddGlobalVariable("BuyPrice", Types.Double, 0);

AddGlobalVariable("CurrentQ", Types.Double, 0);

AddGlobalVariable("CurrentStartQ", Types.Double, 0);

AddGlobalVariable("Type", Types.Double, 1);
AddGlobalVariable("UchCena", Types.Double, 0);
AddGlobalVariable("Dohod", Types.Double, 0);
AddGlobalVariable("DohodAkc", Types.Double, 0);
AddGlobalVariable("DohodLot", Types.Double, 0);

AddChartIndicator("MY.str_Invest_Grid_7", new Dictionary <string, string>{{"Price", "MinPrice"},{"PL", "DeltaPercentBuy"},{"PL1", "DeltaPercentBuy1"},{"Delta", "DeltaPercentSell"},{"Delta1", "DeltaPercentSell1"}, {"Type", "Type"}});

}

function OnUpdate()

{

//===========================================================

// 29/02/2025

//===========================================================
Action<string> ShowMessageAndStopRobot = (string Msg) => {
ShowMessage(Msg);
Stop();
};
double pos = CurrentPosition(); // текущая позиция
var lastPriceSorted = new SortedList<double, double>(LastPrice);
double GetQuoteBid = GetQuote().Bid;
double GetQuoteAsk = GetQuote().Ask;
if (GetQuoteBid <= 0) GetQuoteBid = Input.Close[0];
if (GetQuoteAsk <= 0) GetQuoteAsk = Input.Close[0];
double lotSize = LotSize();

if ((TypeQ == 1) && (Q%lotSize != 0 || StartQ%lotSize != 0)) ShowMessageAndStopRobot("StartQ или Q не кратно лоту. Робот остановлен!");
if ((TypeQ == 1) && (Q > LongLimit || StartQ > LongLimit)) ShowMessageAndStopRobot("StartQ или Q больше, чем LongLimit. Робот остановлен!");
if (Q <= 0 || StartQ < 0) ShowMessageAndStopRobot("StartQ < 0 или Q <= 0. Робот остановлен!");
if (DeltaPercentBuy <= 0 || DeltaPercentSell <= 0 ) ShowMessageAndStopRobot("DeltaPercent (Buy or Sell) <= 0. Робот остановлен!");
if (SellAboveThisLevel < 0 || BuyBelowThisLevel < 0) ShowMessageAndStopRobot("SellAboveThisLevel < 0 или BuyBelowThisLevel < 0. Робот остановлен!");
if (pos < 0) ShowMessageAndStopRobot("Текущая позиция < 0. Робот остановлен.");

//===========================================================
if (MaxPriceParam > 0) MaxPrice = MaxPriceParam;
else if(Input1.High[0] > MaxPrice) MaxPrice = Input1.High[0]; // запоминаем максимальный High за всё время работы (не Close)

//===========================================================
UchCena = AverPrice();
Dohod = DohodZakr + Dividend + RealizedPLAfterCommission ();

DohodAkc = Dohod/Input1.Close[0];
DohodLot = DohodAkc/LotSize();

Action SaveGlobalVars = () => {
LastPrice = new Dictionary<double, double>(lastPriceSorted);
LastPriceCount = LastPrice.Count;
xPosition = pos;
UchCena = UchCena;
Dohod = Dohod;

DohodAkc = DohodAkc;
DohodLot = DohodLot;
};
if (TypeQ == 1) {
CurrentQ = Q;
if (!inited) CurrentStartQ = StartQ;
} else if (TypeQ == 2) {
CurrentQ = (int)(Q/Input1.Close[0]/lotSize) * lotSize;
if (!inited && CurrentStartQ <= 0) CurrentStartQ = (int)(StartQ/Input1.Close[0]/lotSize) * lotSize;
} else {
ShowMessageAndStopRobot("TypeQ должен быть равен 1 или 2. Робот остановлен!");
}
// Правило 1. если первый запуск и робот не проинициализирован, покупаем StartQ
if (!inited) {
if (pos < CurrentStartQ) {
if (BuyOK > 0.5) {
if (LongLimitStart == 0) {
LongLimitStart = LongLimit;
SetLongLimit(CurrentStartQ);
}
// Покупка StartQ
EnterLongLimit(Input1.Close[0]*(1.0 + 0.01 * OrderSlippage));
var lastSignal = GetLastSignalInfo();
if (lastSignal != null) {
lastSignalId = lastSignal.SignalID;
} else {
ShowMessageAndStopRobot("Ошибка чтения сигнала =Правило 1=. Робот остановлен.");
}
}
return;
} else {
inited = true;
if (LongLimitStart != 0) SetLongLimit(LongLimitStart);
if (pos > 0) {
var signals = GetSignalInfo(SignalType.Open, (int)pos);
var initSum = signals.Where(s => s.ActionSuperType == AvailableActions.Initialization).Sum(s => s.OperationExecuted * Input.Close[0]);
var boughtSum = signals.Where(s => s.ActionSuperType != AvailableActions.Initialization).Sum(s => s.OperationExecuted * s.PriceOfTrade);
var avp = (initSum + boughtSum) / pos;

while (pos - xPosition > 0) {
if (TypeQ == 1) {
lastPriceSorted.Add(avp, Math.Min(Q, pos - xPosition));
xPosition += Q;
} else {
int qty2process = (int)((int)(1.0*Q/avp/lotSize) * lotSize);
lastPriceSorted.Add(avp, Math.Min(qty2process, pos - xPosition));
xPosition += qty2process;
}
avp *= (1.0 + 0.01*DeltaPercentSell);
}
}
}
SaveGlobalVars();
}

//===========================================================
var activeOrder = GetActiveOrders().LastOrDefault();
if (activeOrder != null && pos == xPosition && activeOrder.QuantityRest != activeOrder.OrderRest) return; //ждём сделки

//===========================================================
//корректировка уровней
if (pos > xPosition) { // позиция увеличилась
while (lastPriceSorted.Count > 0 && lastPriceSorted.First().Value <= 0)
lastPriceSorted.Remove(lastPriceSorted.First().Key);

int Qty2process = 0;
double Lvl = GetSignalInfo(SignalType.Open, (int)(pos - xPosition))[0].PriceOfTrade;

if (lastPriceSorted.Count > 0 &&
CurrentQ > lastPriceSorted.First().Value &&
TypeQ == 1) {
Qty2process = (int)Math.Min(CurrentQ - (int)lastPriceSorted.First().Value, pos - xPosition);
lastPriceSorted[lastPriceSorted.First().Key] += Qty2process;
xPosition += Qty2process;
}
while (pos > xPosition) {
if(lastPriceSorted.ContainsKey(Lvl)) {
if (CurrentQ <= (int)lastPriceSorted[Lvl]) Qty2process = 0; // есть уровень
else Qty2process = (int)Math.Min(CurrentQ - (int)lastPriceSorted[Lvl], pos - xPosition);
lastPriceSorted[Lvl] += Qty2process;
} else { // нет уровня
Qty2process = (int)Math.Min(CurrentQ, pos - xPosition);
lastPriceSorted.Add(Lvl, Qty2process);
}
Lvl *= (1.0 + 0.01*CurrDeltaBuy);
xPosition += Qty2process;
}
} else if (pos < xPosition && lastPriceSorted.Count > 0) { // позиция уменьшилась
int b = (int)xPosition - (int)pos; // неучтенное количество проданных
while (b > 0) {
if (lastPriceSorted.Count == 0) break; // на всякий случай
var firstKey = lastPriceSorted.First().Key;
if (b < lastPriceSorted[firstKey]) {
lastPriceSorted[firstKey] -= b; // исполнили часть уровня
break;
} else {
b -= (int)lastPriceSorted[firstKey]; // исполнили весь уровень
lastPriceSorted.Remove(firstKey);
}
}
}
SaveGlobalVars();

//===========================================================
if (MinPriceParam > 0) MinPrice = MinPriceParam; // корректируемый параметром уровень
else if (lastPriceSorted.Count > 0) MinPrice = lastPriceSorted.First().Key; // текущий уровень, от которого строим коридор
else MinPrice = MaxPrice;

//===========================================================
//корректировка Delta
if (LastPriceCount >= MaxLevels) CurrDeltaBuy = DeltaPercentBuy + (double)(LastPriceCount - MaxLevels + 1) * DeltaIncBuy;
else CurrDeltaBuy = DeltaPercentBuy;
if (LastPriceCount <= MinLevels) CurrDeltaSell = DeltaPercentSell + (double)(MinLevels - LastPriceCount + 1) * DeltaIncSell;
else CurrDeltaSell = DeltaPercentSell;
SellPrice = MinPrice * (1.0 + 0.01 * CurrDeltaSell);

//===========================================================
//Правило 2.1. Если цена упала, восстанавливаем до Q нижний уровень
if (lastPriceSorted.Count > 0 &&
Input1.Close[0] <= lastPriceSorted.First().Key &&
lastPriceSorted.First().Value < CurrentQ &&
LongLimit > pos &&
Input1.Close[0] <= BuyBelowThisLevel &&
BuyOK > 0.5 &&
CurrentQ > 0 &&
TypeQ == 1) { // это обязательное условие
if(activeOrder != null) {
if(activeOrder.OrderDirection != OrderDirection.Buy) CancelActiveOrders(true);
return; // ждём исполнения уже выставленной заявки
}
double pBuy = lastPriceSorted.First().Key;
if (!IsTestMode) pBuy = Math.Min(Math.Min(pBuy, GetQuoteBid * (1.0 + 0.01*QSlippage)), GetFinInfo().UpPrice);
int qBuy = (int)Math.Min(LongLimit - pos, CurrentQ - lastPriceSorted.First().Value);
BuyPrice = pBuy;
EnterLongLimit(pBuy, qBuy);
var lastSignal = GetLastSignalInfo();
if(lastSignal != null) {
lastSignalId = lastSignal.SignalID;
} else {
ShowMessageAndStopRobot("Ошибка чтения сигнала =Правило 2.1=. Робот остановлен.");
}
}

//===========================================================
//Правило 2. Если цена упала, покупаем
if (Math.Min(Input1.Low[0], GetQuoteBid) <= MinPrice*(1.0 - 0.01*DeltaPercentBuy1) &&
pos < LongLimit &&
Input1.Close[0] <= BuyBelowThisLevel &&
BuyOK > 0.5 &&
CurrentQ > 0) {
if(activeOrder != null) {
if(activeOrder.OrderDirection != OrderDirection.Buy) CancelActiveOrders(true);
return; // ждём исполнения уже выставленной заявки
}
double pBuy = MinPrice*(1.0 - 0.01*CurrDeltaBuy + 0.01*OrderSlippage);
if (!IsTestMode) pBuy = Math.Min(Math.Min(pBuy, GetQuoteBid * (1.0 + 0.01*OrderSlippage)), GetFinInfo().UpPrice);
int qBuy = (int)Math.Min(LongLimit - pos, Math.Max(CurrentQ, (int)((MinPrice - pBuy) / MinPrice * 100 / CurrDeltaBuy) * CurrentQ));
BuyPrice = pBuy;
EnterLongLimit(pBuy, qBuy);
var lastSignal = GetLastSignalInfo();
if(lastSignal != null) {
lastSignalId = lastSignal.SignalID;
} else {
ShowMessageAndStopRobot("Ошибка чтения сигнала =Правило 2=. Робот остановлен.");
}
}

//===========================================================
//Правило 3 Продажа при достижении общего целевого уровня
if (Input1.Close[0] >= ClosePositionAtPrice && pos > 0 && ClosePositionAtPrice > 0) {
ClosePosition();
var lastSignal = GetLastSignalInfo();
if(lastSignal != null) {
lastSignalId = lastSignal.SignalID;
} else {
ShowMessageAndStopRobot("Ошибка чтения сигнала =Правило 3=. Робот остановлен.");
}
}

//===========================================================
// Правило 3.2 Если цена выше цены из начала списка, продаем
if (((Input1.High[0] >= MinPrice * (1.0 + 0.01 * DeltaPercentSell1)) || (GetQuoteAsk >= MinPrice * (1.0 + 0.01 * DeltaPercentSell1))) &&
pos > 0 &&
Input1.Close[0] >= SellAboveThisLevel &&
SellOK > 0.5) {

if(activeOrder != null) {
if(activeOrder.OrderDirection != OrderDirection.Sell) CancelActiveOrders(true);

return; // ждём исполнения уже выставленной заявки

}
double pSell = SellPrice;
if (!IsTestMode) pSell = Math.Max(Math.Max(pSell, GetQuoteAsk) * (1.0 - 0.01*OrderSlippage), GetFinInfo().DownPrice);
int qSell = (int)lastPriceSorted.First().Value;
if (qSell > 0) {
CloseLongLimit(pSell, qSell);
var lastSignal = GetLastSignalInfo();
if(lastSignal != null) {
lastSignalId = lastSignal.SignalID;
} else {
ShowMessageAndStopRobot("Ошибка чтения сигнала =Правило 3=. Робот остановлен.");
}
} else {
ShowMessageAndStopRobot(String.Format("Ошибка: qSell <= 0 для CloseLong =Правило 3=. Робот остановлен. qSell= {0}", qSell));
}
}

}

//===========================================================

Установка Робота.

Запускаем "Конструктор Роботов", для этого в окне "Библиотека стратегий" нам нужно нажать кнопку "Новая Стратегия".

№ 9. Новая стратегия.
№ 9. Новая стратегия.

В открывшимся окне нам предоставляется выбор, будем ли мы модернизировать имеющуюся у нас стратегию или будем создавать новую с нуля. Если мы решили модернизировать существующую стратегию, нужно поставить "птичку" Использовать существующую стратегию, и в окошке ниже выбрать из выпадающего списка стратегию которую будем изменять. Нам нужно создать новую стратегию с нуля, поэтому просто жмем кнопку Next.

№ 10.Редактирование стратегий.
№ 10.Редактирование стратегий.

Откроется окно где нам следует задать название нашего Робота, которое должно совпадать с названием в тексте Робота, поэтому вставляем имя SBS_RS_v3 , так же можем сделать тут краткое описание алгоритма, которое будет видно в окне "Библиотека стратегий".

№ 11. Задаем название стратегии.
№ 11. Задаем название стратегии.

далее жмем кнопку Next. И попадаем в окно непосредственного конструирования стратегии. В этом окне жмем кнопку "Исходный код".

№12.
№12.

открывается новое окно. В нем жмем кнопку "разблокировать код".

№ 13.
№ 13.

В открывшемся окне выделяем весь текст и копируем на его место код Робота из статьи.

№ 14.
№ 14.

Затем обязательно нужно нажать кнопку "Компилировать", затем кнопку "Сохранить". если все скопировали правильно мастер стратегий не покажет строчек с ошибками. Жмем кнопку "Next" и можем создавать и запускать Робота.

Какие основные изменения внесены в нового Робота.

Параметрами "SellAboveThisLevel" и "BuyBelowThisLevel" можно задать верхнюю и нижнюю границу диапазона в котором роботу разрешено совершать сделки, по умалчиванию ограничения сняты.

Параметры изменения цены для покупки - продажи и выставления заявок задаются в процентах, а не в десятых долях как ранее.

Параметры "DeltaIncBuy" и "DeltaIncSell" задают на какой процент будет изменяться параметры для покупки - продажи, когда количество набранных уровней станет больше значения заданного параметром "MaxLevels" или меньше числа уровней заданного параметром "MinLevels" соответственно.

Параметром "ClosePositionAtPrice" можно задать цену, при превышении которой Робот закроет всю набранную позицию ( по умалчиванию распродажа отключена).

Установка параметров "BuyOK" и"SellOK" в значение =0, позволяет запретить покупки или продажи соответственно, при этом сделки параметр которых в ноль не установлен продолжат совершаться. Это полезно, допустим когда назначена выплата дивидендов и вы не желаете распродавать набранную позицию, но при этом докупать не против.
Параметры "MaxPriceParam" и "MinPriceParam" лучше не изменять, Они позволяют откорректировать важные глобальные переменные для покупок продаж минуя уровни набранной сетки, но это может нарушить логику работы Робота если внести неправильные изменения, и получим убыточные сделки. Я позже объясню для чего эти параметры были добавлены и для чего они могут понадобиться.

Параметры "DohodZakr" и "Dividend" позволяют записать доход заработанный другим Роботом, если вы его закрыли и создали нового на том же активе, ну и выплаченные дивиденды по активу соответственно. Если конечно вам интересно, сколько Роботы заработали вам денег на конкретном активе и стоит ли его использовать.. например я использую эти значения для увеличения значения Q на часть прибыли заработанной Роботом.

Параметр ""MaxPrice" показывает максимальную цену актива за все время работы Робота.

Параметры "UchCena", "Dohod", "DohodAkc", "DohodLot" показывают учетную цену, общий доход Робота с учетом дохода закрытых Роботов и дивидендов, а так же число акций которые сейчас можно купить на заработанный Роботом доход и число лотов которые можно купить соответственно. Значение параметра "DohodLot" я использую для изменения значения Q пропорционально части дохода заработанного Роботом. В итоге в Роботе который генерирует больший доход на уровне покупается больше актива.

Еще важное дополнение. Робот корректно начинает работать после значительного падения цены и остановке Робота из-за набора максимальной разрешенной позиции или остановки вручную. Для запуска робота достаточно увеличить ему разрешенную для покупки позицию или разрешить покупки при остановке вручную или через параметры "BuyOK" и"SellOK" . Но учитывайте, если вы стазу разрешите ему докупить акций больше значения параметра Q, то робот попытается докупить пропущенные уровни на все максимально возможное разрешенное количество. Если вы просто хотите запустить робота после остановки, разрешайте ему купить акций не больше значения Q, тогда Робот купит только ОДИН уровень, и начнет докупать от него новые уровни если цена упадет вы это разрешите снова увеличив разрешенное количество.

Ну и если вы в процессе работы Робота решите изменить значение Q (число акций покупаемых роботом на уровне) или по какой то причине на уровне у вас будет акций меньше чем параметр Q, Робот сам при возможности докупит акций на последнем уровне до значения нового параметра Q.

PS. Робота я писал для себя, исходя из своих наблюдения и своего понимания принципов получения максимального дохода. Данного Робота выкладываю как есть. Робот не совершает убыточных сделок, по крайней мере за 9 месяцев работы порядка 200 экземпляров одновременно работающих Роботов, убыточных сделок совершено не было.

PS. Я не тестирую роботов на истории, так как Роботов пишу сам, для себя, я им доверяю. Поэтому Роботов тестирую на отдельном реальном счете, в процессе работы наблюдаю как работают внесенные изменения, и какую реальную доходность дают активы. По результатам тестирования Роботов в "боевом" режиме запускаю активы и измененных Роботов на основном счете. Тестовый счет не пополняется, из вне, растет исключительно с доходов заработанных Роботами, поэтому суммы на каждого Робота на тестовом счете несколько ограниченны, хотя за время работы вполне приличные, до 50 000 на робота.