示例#1
0
        private int CalcTradeSharpDealVolume(int srcVolume)
        {
            if (FixedVolume.HasValue && FixedVolume.Value > 0)
            {
                return(FixedVolume.Value);
            }

            // посчитать объем из плеча
            var eqMt4 = mt4Equity ?? 0;

            // ReSharper disable CompareOfFloatsByEqualityOperator
            if (eqMt4 == 0)
            {
                return(0);
            }

            var ownEq = robotContext.AccountInfo.Equity;

            if (ownEq == 0)
            {
                return(0);
            }
            // ReSharper restore CompareOfFloatsByEqualityOperator

            var koeff = PercentScale / 100M * ownEq / eqMt4;

            srcVolume = (int)Math.Round(srcVolume * koeff);

            // выровнять объем
            return(MarketOrder.RoundDealVolume(srcVolume, VolumeRoundType.Ближайшее, 10000, 10000));
        }
示例#2
0
        private void CalcDealVolume()
        {
            var account = AccountStatus.Instance.AccountData ?? new Account
            {
                Equity   = 10000,
                Balance  = 10000,
                Currency = "USD",
                Group    = "Demo"
            };

            var balance  = tbBalance.Text.Replace(" ", "").ToFloatUniformSafe() ?? 10000;
            var leverage = tbOrderLeverage.Text.ToFloatUniformSafe() ?? 1;

            var volumeDepo = balance * leverage;
            // пересчитать в базовую валюту
            string errorStr;
            var    volmBase = DalSpot.Instance.ConvertToTargetCurrency(cbTicker.Text,
                                                                       true, account.Currency, volumeDepo, QuoteStorage.Instance.ReceiveAllData(), out errorStr);

            if (!string.IsNullOrEmpty(errorStr))
            {
                Logger.Error("CalcDealVolume() - ошибка перевода в валюту депо " + cbTicker.Text + " " + errorStr);
            }

            tbResultedVolume.Text = volmBase.HasValue ? volmBase.Value.ToStringUniformMoneyFormat(false) : "-";
            // округлить объем
            var lotSize = DalSpot.Instance.GetMinStepLot(cbTicker.Text, account.Group);

            tbResultRounded.Text = volmBase.HasValue
                                       ? MarketOrder.RoundDealVolume((int)Math.Round(volmBase.Value),
                                                                     ((EnumItem <VolumeRoundType>)cbRoundVolume.SelectedItem).Value,
                                                                     lotSize.a, lotSize.b).ToStringUniformMoneyFormat()
                                       : "-";
        }
示例#3
0
        protected int CalculateVolumeInBaseCurrency(decimal volumeDepo, string tradeTicker,
                                                    VolumeRoundType roundType, QuoteData quoteByTicker = null)
        {
            var volumeBase = volumeDepo;

            var  depoCurx = robotContext.AccountInfo.Currency;
            var  quotes = QuoteStorage.Instance.ReceiveAllData();
            bool inverse, pairsEqual;
            var  tickerTrans = DalSpot.Instance.FindSymbol(tradeTicker, true, depoCurx,
                                                           out inverse, out pairsEqual);

            if (!pairsEqual)
            {
                QuoteData quote;
                if (tickerTrans == tradeTicker && quoteByTicker != null)
                {
                    quote = quoteByTicker;
                }
                else
                {
                    quotes.TryGetValue(tickerTrans, out quote);
                }
                if (quote == null)
                {
                    var msgError = string.Format(
                        "Невозможно рассчитать объем - отсутствует котировка \"{0}\"", tickerTrans);
                    Logger.Info(msgError);
                    return(0);
                }
                var priceTrans = inverse ? 1 / quote.bid : quote.ask;
                volumeBase /= (decimal)priceTrans;
            }

            return(MarketOrder.RoundDealVolume((int)volumeBase, roundType, RoundMinVolume, RoundVolumeStep));
        }
示例#4
0
        /// <summary>
        /// Расчёт объёма сделки в валюте депозита с учётом наличия или отсутствия фиксированного объёма
        /// </summary>
        protected int CalculateVolume(string ticker, decimal?calculateLeverage = null, int?fixedVolm = null)
        {
            int?baseDealVolume = fixedVolm ?? FixedVolume;

            if (!fixedVolm.HasValue || fixedVolm.Value == 0)
            {
                calculateLeverage = calculateLeverage ?? Leverage;
                Account ac;
                robotContext.GetAccountInfo(robotContext.AccountInfo.ID, true, out ac);
                if (ac == null || ac.Equity <= 0)
                {
                    var errorStr = ac == null
                        ? string.Format("Счет {0} не найден", robotContext.AccountInfo.ID)
                        : string.Format("На счете {0} недостаточно средств ({1})",
                                        robotContext.AccountInfo.ID, ac.Equity.ToStringUniformMoneyFormat());

                    Logger.Info(errorStr);
                    return(0);
                }

                var    leverageVolume = ac.Equity * calculateLeverage.Value;
                string error;
                var    depoVolm = DalSpot.Instance.ConvertToTargetCurrency(ticker, true, ac.Currency,
                                                                           (double)leverageVolume, robotContext.QuotesStorage.ReceiveAllData(),
                                                                           out error) ?? 0M;

                if (depoVolm == 0)
                {
                    Logger.InfoFormat("Не удалось перевести средства в валюту депозита. " + error);
                    return(0);
                }

                baseDealVolume = (int)Math.Round(leverageVolume * leverageVolume / depoVolm);
            }

            var roundMinVolm  = RoundMinVolume;
            var roundVolmStep = RoundVolumeStep;

            if (roundMinVolm == 0 || roundVolmStep == 0)
            {
                var minStepLot = DalSpot.Instance.GetMinStepLot(ticker, robotContext.AccountInfo.Group);
                if (roundMinVolm == 0)
                {
                    roundMinVolm = minStepLot.b;
                }
                if (roundVolmStep == 0)
                {
                    roundVolmStep = minStepLot.a;
                }
            }

            var volume = MarketOrder.RoundDealVolume((int)baseDealVolume.Value, RoundType, roundMinVolm, roundVolmStep);

            if (volume == 0)
            {
                Logger.InfoFormat("{0}: OpenDeal({0} {1}) - объем в валюте депозита ({2:f2}) недостаточен", TypeName, ticker, volume);
            }

            return(volume);
        }
示例#5
0
        private void AutoCalcVolume()
        {
            var account = AccountStatus.Instance.AccountData;

            if (account == null)
            {
                return;
            }

            var symbol   = cbCurx.Text;
            var leverage = UserSettings.Instance.DealLeverage ?? 0;

            if (leverage == 0)
            {
                return;
            }

            // из плеча получить объем базовой валюты
            var volmDepo = leverage * account.Equity;

            string errorString;
            var    volmBase = DalSpot.Instance.ConvertToTargetCurrency(symbol, true, account.Currency, (double)volmDepo,
                                                                       QuoteStorage.Instance.ReceiveAllData(), out errorString);

            if (!string.IsNullOrEmpty(errorString))
            {
                return;
            }
            if (!volmBase.HasValue)
            {
                return;
            }

            // оркуглить
            if (UserSettings.Instance.RoundCalculatedDealVolume)
            {
                var lotSize = DalSpot.Instance.GetMinStepLot(symbol, account.Group);
                volmBase = MarketOrder.RoundDealVolume((int)volmBase.Value, UserSettings.Instance.VolumeRoundType,
                                                       lotSize.minVolume, lotSize.volumeStep);
            }

            cbVolume.Text = ((int)volmBase.Value).ToStringUniformMoneyFormat();
        }
示例#6
0
        public override string ActivateScript(string ticker)
        {
            if (!AccountStatus.Instance.isAuthorized)
            {
                MessageBox.Show("Не авторизован");
                return("Не авторизован");
            }
            var account = AccountStatus.Instance.AccountData;

            if (account == null)
            {
                MessageBox.Show("Не авторизован");
                return("Не авторизован");
            }

            var equity = account.Equity;

            if (equity <= 0)
            {
                MessageBox.Show("На счете отсутствуют денежные средства");
                return("На счете отсутствуют денежные средства");
            }

            var     dealSide = side;
            decimal?sl = null, tp = null;
            float?  trailLevel = null, trailTarget = null;

            // предполагаемая цена входа
            var       quotes = QuoteStorage.Instance.ReceiveAllData();
            QuoteData currentQuote;

            quotes.TryGetValue(ticker, out currentQuote);
            var reqPrice = currentQuote == null
                               ? 0
                               : Side == DealType.Buy
                                     ? currentQuote.ask
                                     : currentQuote.bid;

            if (OrderType == ScriptOrderType.Отложенный && currentQuote == null)
            {
                return("Отложенный ордер не создан - нет котировки " + ticker);
            }

            // для отложенного ордера обязательно запросим цену
            decimal priceEnter = 0;
            float   dealPrice  = 0;

            if (RequestSide || OrderType == ScriptOrderType.Отложенный)
            {
                var dlg = new ScriptPartDepoFormDialog(
                    (int)side,
                    currentQuote == null ? (float?)null : currentQuote.bid,
                    OrderType == ScriptOrderType.Отложенный)
                {
                    TradeTicker = ticker
                };
                if (dlg.ShowDialog() == DialogResult.Cancel)
                {
                    return("Отменен");
                }
                priceEnter = dlg.Price ?? 0;
                sl         = dlg.SL;
                tp         = dlg.TP;
                dealSide   = (DealType)dlg.Side;

                if (dlg.Trailing != null && dlg.Trailing.Length == 2 && (dlg.Trailing[0] != 0 || dlg.Trailing[1] != 0))
                {
                    if (currentQuote == null)
                    {
                        var msg = string.Format("Нет котировки \"{0}\" для расчета пп трейлинга", ticker);
                        MessageBox.Show(msg);
                        return(msg);
                    }

                    var trailPrice = dlg.Trailing[0];
                    dealPrice =
                        OrderType == ScriptOrderType.Отложенный ? (float)priceEnter : (dealSide == DealType.Buy ? currentQuote.ask : currentQuote.bid);
                    var trailPips = DalSpot.Instance.GetPointsValue(ticker, ((int)dealSide) * (trailPrice - dealPrice));

                    // преобразовать цену в пп от входа
                    trailLevel  = trailPips;
                    trailTarget = dlg.Trailing[1];
                }
            }

            // объем в валюте депозита
            var volumeDepo = equity * leverage;
            var volumeBase = volumeDepo;

            // из объема депо пересчитать в объем базовой валюты
            var depoCurx = AccountStatus.Instance.AccountData.Currency;

            bool inverse, pairsEqual;
            var  tickerTrans = DalSpot.Instance.FindSymbol(ticker, true, depoCurx,
                                                           out inverse, out pairsEqual);

            if (!pairsEqual)
            {
                QuoteData quote;
                quotes.TryGetValue(tickerTrans, out quote);
                if (quote == null)
                {
                    var msgError = string.Format(
                        "Невозможно рассчитать объем - отсутствует котировка \"{0}\"", tickerTrans);
                    MessageBox.Show(msgError);
                    return(msgError);
                }
                var priceTrans = inverse ? 1 / quote.bid : quote.ask;
                volumeBase /= (decimal)priceTrans;
            }

            // округлить объем
            var lotSize = DalSpot.Instance.GetMinStepLot(ticker, account.Group);

            volumeBase = MarketOrder.RoundDealVolume((int)volumeBase, VolumeRound,
                                                     lotSize.minVolume, lotSize.volumeStep);
            if (volumeBase == 0)
            {
                var msgError = $"Рассчетный объем входа ({volumeBase}) меньше допустимого ({lotSize.minVolume})";
                MessageBox.Show(msgError);
                return(msgError);
            }

            // проверить количество входов (по тикеру либо вообще)
            var ordersCount =
                DealCounting == DealCountingType.ОбщийУчет
                    ? MarketOrdersStorage.Instance.MarketOrders.Count
                    : MarketOrdersStorage.Instance.MarketOrders.Count(o => o.Symbol == ticker);

            if (ordersCount >= dealsMax)
            {
                var msgError =
                    DealCounting == DealCountingType.ОбщийУчет
                    ? $"Уже открыто {ordersCount} сделок из {dealsMax} макс."
                        : $"По \"{ticker}\" уже открыто {ordersCount} сделок из {dealsMax} макс.";
                MessageBox.Show(msgError);
                return(msgError);
            }

            // подтверждение
            var confirmPrice = dealPrice;

            if (confirmPrice == 0)
            {
                confirmPrice = (dealSide == DealType.Buy ? currentQuote.ask : currentQuote.bid);
            }

            if (confirmTrade)
            {
                if (MessageBox.Show(string.Format("Будет совершена {0} {1} {2} по {3}. Продолжить?",
                                                  dealSide == DealType.Buy ? "покупка" : "продажа",
                                                  volumeBase.ToStringUniformMoneyFormat(), depoCurx,
                                                  confirmPrice.ToStringUniformPriceFormat()),
                                    "Подтверждение", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    return("отменено пользователем");
                }
            }

            // таки войти в рынок
            if (OrderType == ScriptOrderType.ыночный)
            {
                MainForm.Instance.SendNewOrderRequestSafe(
                    RequestUniqueId.Next(),
                    AccountStatus.Instance.accountID,
                    new MarketOrder
                {
                    Volume       = (int)volumeBase,
                    Side         = (int)dealSide,
                    Symbol       = ticker,
                    StopLoss     = (float?)sl,
                    TakeProfit   = (float?)tp,
                    TrailLevel1  = trailLevel,
                    TrailTarget1 = trailTarget
                },
                    priceEnter, 0, Contract.Entity.OrderType.Market);
            }
            else
            {
                // создать отложенник
                var orderType = PendingOrderType.Limit;
                if (((int)dealSide == 1 && currentQuote.ask < (float)priceEnter) ||
                    ((int)dealSide == -1 && currentQuote.bid > (float)priceEnter))
                {
                    orderType = PendingOrderType.Stop;
                }
                var pendingOrder = new PendingOrder
                {
                    AccountID    = AccountStatus.Instance.accountID,
                    Symbol       = ticker,
                    Volume       = (int)volumeBase,
                    Side         = (int)dealSide,
                    PriceSide    = orderType,
                    PriceFrom    = (float)priceEnter,
                    StopLoss     = (float?)sl,
                    TakeProfit   = (float?)tp,
                    TrailLevel1  = trailLevel,
                    TrailTarget1 = trailTarget
                };

                MainForm.Instance.SendNewPendingOrderRequestSafe(RequestUniqueId.Next(), pendingOrder);
            }

            return("Сделка с фиксированным плечом (" + dealSide + " " + ticker + ") совершена");
        }
示例#7
0
        public static int GetNewOrderVolume(TradeSignalActionTrade action,
                                            TradeSharpConnection ctx, SUBSCRIPTION_SIGNAL tradeSets)
        {
            // получить ордера по счету, посчитать актуальный баланс (средства) счета
            try
            {
                var account = ctx.ACCOUNT.FirstOrDefault(a => a.ID == tradeSets.TargetAccount.Value);
                if (account == null)
                {
                    Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: счет не найден",
                                       tradeSets.TargetAccount, action.OrderId);
                    return(0);
                }

                var equity = (double)account.Balance;

                // ордера
                var orders = ctx.POSITION.Where(p => p.AccountID == tradeSets.TargetAccount &&
                                                p.State == (int)PositionState.Opened).ToList().Select(o => LinqToEntity.DecorateOrder(o)).ToList();

                // проверить - нет ли противоположного ордера?
                var quotes = Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData();

                if (orders.Count > 0)
                {
                    if (!(tradeSets.HedgingOrdersEnabled ?? false))
                    {
                        var hasOrdersCounter = orders.Any(p => p.Symbol == action.Ticker && p.Side != action.Side);
                        if (hasOrdersCounter)
                        {
                            logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info, LogMsgContraOrders,
                                                                  1000 * 60 * 90, "Ордер {0} {1}, счет {2} - есть встречные ордера",
                                                                  action.Side > 0 ? "BUY" : "SELL", action.Ticker, tradeSets.TargetAccount);
                            return(0);
                        }
                    }

                    // посчитать профит по позам
                    bool noQuoteError;
                    var  openResult = DalSpot.Instance.CalculateOpenedPositionsCurrentResult(
                        orders, quotes, account.Currency, out noQuoteError);
                    if (noQuoteError)
                    {
                        logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmCalcNoQuote,
                                                              1000 * 60 * 90, "GetNewOrderVolume - нет котировки");
                        return(0);
                    }
                    equity += openResult;
                }

                if (equity <= 0)
                {
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgEquityIsNil,
                                                          1000 * 60 * 90, "Баланс счета {0}: {1}", account.ID, equity);
                    return(0);
                }

                // посчитать объем
                var volumeDepo = (tradeSets.PercentLeverage ?? 100) / 100f * equity * (double)action.Leverage;
                // пересчитать объем в базовую валюту
                string errorStr;
                var    volumeBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency, volumeDepo,
                                                                             quotes, out errorStr);
                if (!volumeBase.HasValue)
                {
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmToBase,
                                                          1000 * 60 * 90, "GetNewOrderVolume - невозможно посчитать объем по сделке {0}, валюта счета {1}: {2}",
                                                          action.Ticker, account.Currency, errorStr);
                    return(0);
                }

                // округлить объем
                var volume = MarketOrder.RoundDealVolume((int)volumeBase,
                                                         (VolumeRoundType)(tradeSets.VolumeRound ?? (int)VolumeRoundType.Ближайшее),
                                                         tradeSets.MinVolume ?? 10000, tradeSets.StepVolume ?? 10000);
                if (volume == 0)
                {
                    var msg = string.Format("Полученный объем входа ({0}) округлен до 0", (int)volumeBase);
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error,
                                                          LogMsgVolmRoundToZero, 1000 * 60 * 90, msg);
                    return(0);
                }

                // проверить на превышение плеча
                if ((tradeSets.MaxLeverage ?? 0) > 0)
                {
                    var totalExposure     = 0M;
                    var ordersBySignaller = orders.Where(position =>
                    {
                        int orderSignalCatId, parentDealId;
                        if (MarketOrder.GetTradeSignalFromDeal(position, out orderSignalCatId, out parentDealId))
                        {
                            return(orderSignalCatId == action.ServiceId);
                        }
                        return(false);
                    }).GroupBy(o => o.Symbol).ToDictionary(o => o.Key, o => o.ToList());

                    foreach (var orderByTicker in ordersBySignaller)
                    {
                        // суммарная экспозиция
                        var exp = orderByTicker.Value.Sum(o => o.Side * o.Volume);
                        if (orderByTicker.Key == action.Ticker)
                        {
                            exp += action.Side * volume;
                        }
                        if (exp == 0)
                        {
                            continue;
                        }

                        // перевести экспозицию в валюту депозита
                        var expBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency,
                                                                               volumeDepo,
                                                                               quotes, out errorStr);
                        if (!expBase.HasValue)
                        {
                            logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgExposureNoQuote,
                                                                  1000 * 60 * 90,
                                                                  "GetNewOrderVolume - невозможно посчитать экспозицию по сделке " +
                                                                  "{0}, тикер {1}: {2}",
                                                                  action.Ticker, orderByTicker.Key, errorStr);
                            return(0);
                        }

                        totalExposure += Math.Abs(expBase.Value);
                    }
                    var totalLeverage = (double)totalExposure / equity;
                    // ReSharper disable PossibleInvalidOperationException
                    if (totalLeverage > tradeSets.MaxLeverage.Value)
                    // ReSharper restore PossibleInvalidOperationException
                    {
                        logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgMaxLevExceeded,
                                                              1000 * 60 * 90,
                                                              "GetNewOrderVolume - макс плечо ({0}) превышено, " +
                                                              "тикер {1}: плечо составит {2}",
                                                              tradeSets.MaxLeverage.Value,
                                                              action.Ticker, totalLeverage);
                        return(0);
                    }
                }

                return(volume);
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: {2}",
                                   tradeSets.TargetAccount, action.OrderId, ex);
            }

            return(0);
        }
        public override string ActivateScript(string ticker)
        {
            if (!AccountStatus.Instance.isAuthorized)
            {
                MessageBox.Show("Не авторизован");
                return("Не авторизован");
            }
            var equity = AccountStatus.Instance.AccountData.Equity;

            if (equity <= 0)
            {
                MessageBox.Show("На счете отсутствуют денежные средства");
                return("На счете отсутствуют денежные средства");
            }

            var   orders = MarketOrdersStorage.Instance.MarketOrders.Where(o => o.Symbol == ticker).ToList();
            var   side   = orders.Count == 0 ? DealType.Buy : (DealType)orders[0].Side;
            float?sl     = orders.Count == 0 ? null : orders[0].StopLoss;

            // открыть окно выбора направления входа и SL
            var dlg = new TradeFromSLDlg(orders.Count, side, sl);

            if (dlg.ShowDialog() != DialogResult.OK)
            {
                return("Отменено пользователем");
            }
            side = dlg.Side;
            var targetSl = dlg.StopLoss;

            // выставить стоп остальным ордерам
            foreach (var order in orders)
            {
                var delta       = Math.Abs((order.StopLoss ?? 0) - targetSl);
                var deltaPoints = DalSpot.Instance.GetPointsValue(ticker, delta);
                if (deltaPoints < 2)
                {
                    continue;
                }

                // редактировать ордер
                order.StopLoss = targetSl;
                MainForm.Instance.SendEditMarketRequestSafe(order);
            }

            // получить текущую цену
            var       quotes = QuoteStorage.Instance.ReceiveAllData();
            QuoteData quote;

            quotes.TryGetValue(ticker, out quote);
            if (quote == null)
            {
                return("Нет котировки " + ticker);
            }

            // коэфф пересчета из контрвалюты в валюту депо
            var kCounterDepo = 1f;

            if (!ticker.EndsWith("USD"))
            {
                kCounterDepo = 1 / ((quote.ask + quote.bid) * 0.5f);
            }
            // посчитать макс. допустимый объем входа исходя из просадки
            var ordersResult = orders.Sum(o => o.Volume * o.Side * (targetSl - o.PriceEnter) * kCounterDepo); // убыток (прибыль) по сделкам

            var     priceEnter   = side == DealType.Buy ? quote.ask : quote.bid;
            var     orderLossAbs = ((int)side) * (decimal)(targetSl - priceEnter);
            decimal volumeMax    = decimal.MaxValue;

            // от текущего баланса считать сумму потерь
            var loss = equity * lossPercent / 100;

            if (orderLossAbs < 0)
            {
                volumeMax = (decimal)kCounterDepo * (loss + (decimal)ordersResult) / (-orderLossAbs);
            }

            // вход невозможен
            if (volumeMax < 0)
            {
                var err = string.Format(
                    "Потери по уже открытым позициям для SL {0:f4} ({1:f0}) превысят допустимый процент " +
                    "потерь ({2:f1}%, {3:f0} USD)", targetSl, ordersResult, lossPercent, loss);
                MessageBox.Show(err);
                return(err);
            }

            // множитель для объема
            var indexK = orders.Count;

            if (indexK >= volumePercent.Length)
            {
                indexK = volumePercent.Length - 1;
            }
            var koeffVolume = volumePercent[indexK];

            if (volumeMax < decimal.MaxValue)
            {
                volumeMax *= (koeffVolume / 100M);
            }

            // сравнить объем с предельно допустимым
            var maxVolumeDepo = equity * LeverageMax;
            var maxVolumeBase = maxVolumeDepo / (decimal)((quote.bid + quote.ask) * 0.5f);

            var volumeEnter = Math.Min(volumeMax, maxVolumeBase);

            // округлить объем
            var volume = MarketOrder.RoundDealVolume((int)volumeEnter, VolumeRound,
                                                     volumeMin, volumeStep);

            if (volume == 0)
            {
                var err = string.Format("Объем входа ({0:f0}) после округления равен 0",
                                        volumeEnter);
                MessageBox.Show(err);
                return(err);
            }

            // подтвердить вход)
            if (confirmTrade)
            {
                var orderLoss = volume * ((int)side) * (targetSl - priceEnter);
                var lossStr   = ordersResult != 0
                                  ? string.Format("{0}{1:f0} по уже открытым ордерам и {2:f0} по новому ордеру",
                                                  ordersResult > 0 ? "прибыль" : "", Math.Abs(ordersResult), (-orderLoss))
                                  : (-orderLoss).ToString("f0");
                var prompt = string.Format("Будет открыта позиция: {0} {1} {2}, SL={3:f4}. Потери при SL: {4}. Продолжить?",
                                           side, volume, ticker, targetSl, lossStr);
                if (MessageBox.Show(prompt, "Подтвердить сделку", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    return("Отменено пользователем");
                }
            }

            // войти в рынок
            MainForm.Instance.SendNewOrderRequestSafe(
                RequestUniqueId.Next(),
                AccountStatus.Instance.accountID,
                new MarketOrder
            {
                Volume   = volume,
                Side     = (int)side,
                Symbol   = ticker,
                StopLoss = targetSl
            },
                (decimal)priceEnter, 0, OrderType.Market);

            return("Операция успешна");
        }