/// <summary>
        /// посчитать профит по открытым позам в валюте депозита
        /// </summary>
        private float CalculateAccountOpenProfit(TradeSharpConnection ctx,
                                            ACCOUNT account, Dictionary<string, CandleData> candles)
        {
            var profitOpen = 0f;
            foreach (var pos in ctx.POSITION.Where(p => p.AccountID == account.ID))
            {
                // найти последнюю котировку
                CandleData candle;
                if (!candles.TryGetValue(pos.Symbol, out candle))
                {
                    Errors.Add("CalculateAccountOpenProfit - " + Resource.ErrorMessageNoExitPriceFor + " " + pos.Symbol);
                    continue;
                }

                // получить профит по позиции
                var priceExit = pos.Side > 0
                                    ? candle.close
                                    : DalSpot.Instance.GetAskPriceWithDefaultSpread(pos.Symbol, candle.close);
                var profitCounter = pos.Volume * pos.Side * (priceExit - (float)pos.PriceEnter);

                // перевести профит в валюту депо
                if (!ConvertBaseOrCounterDepo(false, pos.Symbol, account.Currency, candles, ref profitCounter))
                    continue;
                profitOpen += profitCounter;
            }
            return profitOpen;
        }
        public string EditSpotItem(TradeSharpConnection context, SpotModel model)
        {
            var result = string.Empty;
            var newContext = EnsureContext(ref context);
            try
            {
                var itemToEdit = context.SPOT.Single(x => x.Title == model.Title);

                itemToEdit.ComBase = model.ComBase;
                itemToEdit.ComCounter = model.ComCounter;
                itemToEdit.Title = model.Title;
                itemToEdit.CodeFXI = model.CodeFXI;
                itemToEdit.MinVolume = model.MinVolume;
                itemToEdit.MinStepVolume = model.MinStepVolume;
                itemToEdit.Precise = model.Precise;
                itemToEdit.SwapBuy = model.SwapBuy;
                itemToEdit.SwapSell = model.SwapSell;
                itemToEdit.Description = model.Description;

                context.SaveChanges();
            }
            catch (Exception ex)
            {
                Logger.Error("EditSpotItem()", ex);
                result = ex.Message;
            }
            finally
            {
                if (newContext != null) newContext.Dispose();
            }
            return result;
        }
        public string AddNewSpotItem(TradeSharpConnection context, SpotModel model)
        {
            var result = string.Empty;
            var newContext = EnsureContext(ref context);
            try
            {
                var spot = new SPOT
                {
                    ComBase = model.ComBase,
                    ComCounter = model.ComCounter,
                    Title = model.Title,
                    CodeFXI = model.CodeFXI,
                    MinVolume = model.MinVolume,
                    MinStepVolume = model.MinStepVolume,
                    Precise = model.Precise,
                    SwapBuy = model.SwapBuy,
                    SwapSell = model.SwapSell,
                    Description = model.Description
                };

                context.SPOT.Add(spot);
                context.SaveChanges();
            }
            catch (Exception ex)
            {
                Logger.Error("AddNewSpotItem()", ex);
                result = ex.Message;
            }
            finally
            {
                if (newContext != null) newContext.Dispose();
            }
            return result;
        }
        /// <summary>
        /// добавить маркапы и прочее шкурилово
        /// </summary>
        public static void ProcessOrderClosing(MarketOrder order,
            ACCOUNT account,
            ORDER_BILL bill, 
            TradeSharpConnection ctx,
            Dictionary<string, QuoteData> quotes, string brokerCurrency)
        {
            //Logger.Info("BillingManager.ProcessOrderClosing()");
            try
            {
                // перевести маркапы в валюту брокера
                var markupSum = bill.MarkupExit + bill.MarkupEnter;
                // в контрвалюте...
                if (markupSum != 0)
                    markupSum = order.Volume * markupSum;
                Logger.Info("BillingManager: markupSum is " + markupSum);

                // перевести в валюту брокера
                var resultCounter = order.Side * order.Volume * (order.PriceExit.Value - order.PriceEnter);
                var rateCounterDepo = resultCounter == 0 ? 1 : order.ResultDepo / resultCounter;
                // валюта брокера к контрвалюте
                var rateCounterBroker = rateCounterDepo;
                Logger.Info("BillingManager: rateCounterDepo is " + rateCounterDepo);

                if (account.Currency != brokerCurrency)
                {
                    // пример: позиция EURCAD, валюта брокера USD
                    // надо получить курс CADUSD
                    var markupBroker = (float) markupSum;
                    string errorStr;
                    var resultedMarkup = DalSpot.Instance.ConvertToTargetCurrency(order.Symbol, false, brokerCurrency,
                                                                            markupBroker, quotes, out errorStr, true);

                    if (!resultedMarkup.HasValue)
                    {
                        Logger.ErrorFormat("BillingManager.ProcessOrderClosing - невозможно перевести профит по {0} в {1}: {2}",
                            order.Symbol, brokerCurrency, errorStr);
                        return;
                    }
                    markupBroker = (float)resultedMarkup.Value;
                    rateCounterBroker = (float)(markupBroker / markupSum);
                    markupSum = markupBroker;
                }
                else
                    markupSum *= rateCounterBroker;
                bill.MarkupBroker = markupSum;
                bill.ProfitBroker = resultCounter * rateCounterBroker;
                Logger.InfoFormat("BillingManager: MarkupBroker: {0}, ProfitBroker: {1}",
                    bill.MarkupBroker, bill.ProfitBroker);

                // сохранить билль
                ctx.Entry(bill).State = EntityState.Modified;
                Logger.InfoFormat("BillingManager:OK");
            }
            catch (Exception ex)
            {
                Logger.Error("BillingManager.ProcessOrderClosing() - ошибка редактирования счета", ex);
            }
        }
        public ACCOUNT_SHARE_HISTORY CalculateAccountShare(TradeSharpConnection ctx,
                                                           ACCOUNT_SHARE share,
                                                           ACCOUNT_SHARE ownerShare,
                                                           ref decimal ownersMoney,
                                                           decimal equity, 
                                                           PaidService serviceWithFeeScale,
                                                           out bool feeWasTaken)
        {
            feeWasTaken = false;
            var shareMoney = equity*share.Share/100M;
            var hist = new ACCOUNT_SHARE_HISTORY
                {
                    Account = share.Account,
                    Date = DateTime.Now,
                    OldShare = share.Share,
                    OldHWM = share.HWM,
                    NewShare = share.Share,
                    NewHWM = Math.Max(share.HWM ?? 0, shareMoney),
                    ShareOwner = share.ShareOwner,
                    ShareAmount = shareMoney
                };

            share.HWM = hist.NewHWM;
            if ((hist.OldHWM ?? 0) == 0)
                return hist;
            if (shareMoney <= hist.OldHWM)
                return hist;
            if (serviceWithFeeScale == null)
                return hist;

            // был установлен новый HWM?
            var aboveHwm = shareMoney - hist.OldHWM.Value;
            // посчитать сумму комиссии
            var fee = serviceWithFeeScale.CalculateFee(shareMoney, aboveHwm);
            if (fee < 0.01M) return hist;

            feeWasTaken = true;

            // этот самый кусочек приписать владельцу и списать его с пайщика
            ownersMoney += fee;
            shareMoney -= fee;
            ownerShare.Share = ownersMoney*100M/equity;
            share.Share = shareMoney*100M/equity;

            var newHwm = shareMoney;
            if (newHwm > share.HWM)
            {
                share.HWM = newHwm;
                hist.NewHWM = newHwm;
            }
            return hist;
        }
 public WalletError ChargeFeeOnSubscription(TradeSharpConnection ctx, int serviceId, int usr, bool renewSubscription)
 {
     SERVICE service;
     try
     {
         service = ctx.SERVICE.First(s => s.ID == serviceId);
     }
     catch (Exception ex)
     {
         Logger.Error("Ошибка в ChargeFeeOnSubscription() - сервис не найден", ex);
         return WalletError.InvalidData;
     }
     return ChargeFeeOnSubscription(ctx, service, usr, renewSubscription);
 }
 /// <summary>
 /// Получить с сервера описание всех дилеров, используя уже имеющийся контекст (что бы не пересоздавать его лишний раз)
 /// </summary>
 /// <param name="ctx">контекст</param>
 /// <returns>перечисление диллеров</returns>
 public IEnumerable<DealerDescription> GetAllDealerDescription(TradeSharpConnection ctx)
 {
     Logger.Info(string.Format("попытка запроса описания всех дилеров и их мапинг в класс {0}", typeof(DealerDescription).Name));
     var dealerDescription = new List<DealerDescription>();
     try
     {
         foreach (var dealer in ctx.DEALER)
             dealerDescription.Add(LinqToEntity.DecorateDealerDescription(dealer));
     }
     catch (Exception ex)
     {
         Logger.Error("GetAllDealerDescription()", ex);
         return new List<DealerDescription>();
     }
     return dealerDescription;
 }
 private static decimal AmendDeal(POSITION_CLOSED deal, TradeSharpConnection conn, decimal deltaAmount)
 {
     // "поправить" сделку
     deal.Side = - deal.Side;
     deal.ResultDepo = - deal.ResultDepo;
     var bc = conn.BALANCE_CHANGE.FirstOrDefault(b => b.Position == deal.ID);
     if (bc != null)
     {
         bc.ChangeType = (int) BalanceChangeType.Profit;
         var trans = conn.TRANSFER.FirstOrDefault(t => t.BalanceChange == bc.ID);
         deltaAmount += (bc.Amount*2);
         if (trans != null)
         {
             trans.Amount = -trans.Amount;
             trans.TargetAmount = -trans.TargetAmount;
         }
     }
     return deltaAmount;
 }
 public string DeleteSpotItem(TradeSharpConnection context, string title)
 {
     var result = string.Empty;
     var newContext = EnsureContext(ref context);
     try
     {
         var itemToDel = context.SPOT.Single(x => x.Title == title);
         context.SPOT.Remove(itemToDel);
         context.SaveChanges();
     }
     catch (Exception ex)
     {
         Logger.Error("DeleteSpotItem()", ex);
         result = ex.Message;
     }
     finally
     {
         if (newContext != null) newContext.Dispose();
     }
     return result;
 }
Beispiel #10
0
 /// <summary>
 /// вызывается для нового, только что созданного ордера
 /// создает запись по ордеру
 /// </summary>
 public static void SaveNewOrderBill(OrderBill bill, int positionId, TradeSharpConnection ctx)
 {
     bill.Position = positionId;
     ctx.ORDER_BILL.Add(LinqToEntity.UndecorateOrderBill(bill));
 }
 public bool UpdateAccountBalance(TradeSharpConnection ctx,
     ACCOUNT account, decimal amount, BalanceChangeType changeType,
     string description, DateTime valueDate, int? positionId)
 {
     var bc = new BALANCE_CHANGE
     {
         AccountID = account.ID,
         Amount = amount,
         ChangeType = (int)changeType,
         Description = description,
         ValueDate = valueDate,
         Position = positionId
     };
     try
     {
         ctx.BALANCE_CHANGE.Add(bc);
         account.Balance += ((changeType == BalanceChangeType.Deposit ||
             changeType == BalanceChangeType.Profit) ? amount : -amount);
         ctx.SaveChanges();
         return true;
     }
     catch (Exception ex)
     {
         Logger.ErrorFormat("Ошибка обновления баланса счета {0} на сумму {1}: {2}",
             account.ID, amount, ex);
         return false;
     }
 }
Beispiel #12
0
        public static ORDER_BILL ProcessPriceForOrderClosing(MarketOrder order, Account account,
            TradeSharpConnection ctx)
        {
            AccountGroup.MarkupType markType;
            var spreadDelta = AcccountMarkupDictionary.GetMarkupAbs(account.Group, order.Symbol, out markType);
            var markupExit = 0f;
            if (spreadDelta > 0 && markType != AccountGroup.MarkupType.NoMarkup)
            {
                markupExit = spreadDelta;
                if (markType == AccountGroup.MarkupType.Markup)
                    order.PriceExit -= spreadDelta * order.Side;
            }

            var bill = ctx.ORDER_BILL.FirstOrDefault(b => b.Position == order.ID);
            if (bill != null)
                bill.MarkupExit = markupExit;
            //else
            //    Logger.Debug("Markup: ProcessPriceForOrderClosing - can not find the bill for pos " + order.ID);

            return bill;
        }
        /// <summary>
        /// Пересчёт баланса для указанного счёта. Применяется, например, после отмены уже закрытых сделок
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="accountId">уникаьлный идентификатор счёта, для которого пересчитываем баланс</param>
        public bool ReCalculateAccountBalance(TradeSharpConnection ctx, int accountId)
        {
            try
            {
                Logger.Info(string.Format("Пытыемся пересчитать баланс для счёта {0}", accountId));
                var bal = ctx.BALANCE_CHANGE.Where(b => b.AccountID == accountId).Sum(c =>
                                                                                      (c.ChangeType ==(int)BalanceChangeType.Deposit ||
                                                                                       c.ChangeType ==(int)BalanceChangeType.Profit ||
                                                                                       c.ChangeType ==(int) BalanceChangeType.Swap ? 1: -1)*c.Amount);

                var acc = ctx.ACCOUNT.Single(a => a.ID == accountId);
                acc.Balance = bal;
                ctx.SaveChanges();

                return true;
            }
            catch (InvalidOperationException ex)
            {
                Logger.Error(string.Format(
                        "ReCalculateAccountBalance(). Не удалось пересчитать балланс {0}. Возможно нет ни одной проводки по счёту.",accountId), ex);
            }
            catch (Exception ex)
            {

                Logger.Error(string.Format("ReCalculateAccountBalance(). Не удалось пересчитать балланс счёта {0}.", accountId),ex);
            }
            return false;
        }
        /// <summary>
        /// Метод пересчитывает баланс во всех операциях, кроме закрытия или отмены сделок
        /// </summary>
        public void UpdateBalanceChange(TradeSharpConnection ctx, MarketOrder closedPos, bool deleteTransferOnly)
        {
            // поправить трансфер по счету и баланс
            var dealDescr = string.Format("{1} #{0}", closedPos.ID, Resource.TitleMarketOrderResult);
            var trans = ctx.BALANCE_CHANGE.FirstOrDefault(c => c.AccountID == closedPos.AccountID &&
                                                               (c.ChangeType ==
                                                                (int)BalanceChangeType.Profit ||
                                                                c.ChangeType ==
                                                                (int)BalanceChangeType.Loss) && c.Description.Equals(dealDescr, StringComparison.OrdinalIgnoreCase));
            if (deleteTransferOnly)
            {
                if (trans == null) return;
                ctx.BALANCE_CHANGE.Remove(trans);
            }
            else
            {
                // изменить или добавить перевод
                if (trans == null)
                {
                    trans = new BALANCE_CHANGE { Description = dealDescr, AccountID = closedPos.AccountID };
                    ctx.BALANCE_CHANGE.Add(trans);
                }
                trans.Amount = (decimal)Math.Abs(closedPos.ResultDepo);
                trans.ChangeType = closedPos.ResultDepo > 0
                                       ? (int)BalanceChangeType.Profit
                                       : (int)BalanceChangeType.Loss;
                if (closedPos.TimeExit != null)
                    trans.ValueDate = closedPos.TimeExit.Value;
            }

            //ctx.BALANCE_CHANGE.ApplyCurrentValues(trans);
            ctx.SaveChanges();
        }
 private static void CorrectBalance(int acId, decimal deltaAmount, TradeSharpConnection conn)
 {
     // поправить депозит
     var bc = new BALANCE_CHANGE
     {
         AccountID = acId,
         ValueDate = DateTime.Now,
         Amount = deltaAmount,
         ChangeType = (int) BalanceChangeType.Withdrawal,
         Description = "public offering"
     };
     conn.BALANCE_CHANGE.Add(bc);
     conn.SaveChanges();
     var userId = conn.PLATFORM_USER_ACCOUNT.First(a => a.Account == acId).PlatformUser;
     var tr = new TRANSFER
     {
         ValueDate = bc.ValueDate,
         BalanceChange = bc.ID,
         Amount = -deltaAmount,
         Comment = "public offering",
         User = userId,
         TargetAmount = - deltaAmount
     };
     conn.TRANSFER.Add(tr);
 }
Beispiel #16
0
        private RequestStatus CheckCredentials(string hash, string userLogin, long localTime, int accountId, bool checkTradeRights,
            TradeSharpConnection connection = null)
        {
            try
            {
                var ctx = connection ?? DatabaseContext.Instance.Make();
                try
                {
                    var user = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == userLogin);
                    if (user == null) return RequestStatus.IncorrectData;

                    var userHash = CredentialsHash.MakeCredentialsHash(userLogin, user.Password, localTime);
                    if (userHash != hash)
                        return RequestStatus.IncorrectData;

                    if (!ctx.PLATFORM_USER_ACCOUNT.Any(pa => pa.PlatformUser == user.ID && pa.Account == accountId &&
                                                             (!checkTradeRights ||
                                                              pa.RightsMask == (int) AccountRights.Управление)))
                        return RequestStatus.Unauthorized;
                }
                finally
                {
                    if (connection == null)
                        ctx.Dispose();
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в CheckCredentials()", ex);
                return RequestStatus.ServerError;
            }
            return RequestStatus.OK;
        }
 private void PerformStopout(ACCOUNT ac, Dictionary<string, QuoteData> quotes,
     TradeSharpConnection ctx)
 {
     try
     {
         var sb = new StringBuilder();
         var posReq = from pos in ctx.POSITION where pos.AccountID == ac.ID
                          && pos.State == (int)PositionState.Opened select pos;
         var totalCount = 0;
         var closedCount = 0;
         foreach (var pos in posReq)
         {
             totalCount++;
             // закрыть ордер
             QuoteData quote;
             quotes.TryGetValue(pos.Symbol, out quote);
             var price = quote == null ? 0 : quote.GetPrice(pos.Side > 0 ? QuoteType.Bid : QuoteType.Ask);
             if (price == 0)
             {
                 sb.AppendFormat("Невозможно закрыть ордер {0} ({1}): нет цены", pos.ID, pos.Symbol);
                 continue;
             }
             if (orderRepository.CloseOrder(LinqToEntity.DecorateOrder(pos),
                                                        (decimal) price, PositionExitReason.Stopout))
                 closedCount++;
             sb.AppendFormat("позиция {0} закрыта по цене {1:f4} - стопаут. ", pos.ID, price);
         }
         if (ShouldLogStopout(ac.ID))
             Logger.Info(string.Format("Счет {0}. Закрыто {1} из {2} позиций. ", ac.ID, closedCount, totalCount) + sb);
     }
     catch (Exception ex)
     {
         loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMagicStopout, 60 * 1000,
             "Ошибка при выполнении стопаута {0}: {1}", ac.ID, ex);
     }
 }
Beispiel #18
0
 private PaidService GetPaidServiceProgressiveFeeScaleDetail(TradeSharpConnection ctx, SERVICE srv)
 {
     var fees = ctx.SERVICE_RATE.Where(r => r.Service == srv.ID).OrderBy(r => r.UserBalance).ToList();
         if (fees.Count == 0) return null;
         var service = LinqToEntity.DecoratePaidService(srv);
         service.serviceRates = fees.Select(f => new PaidServiceRate
             {
                 Amount = f.Amount,
                 RateType = PaidServiceRate.ServiceRateType.Percent,
                 UserBalance = f.UserBalance
             }).ToList().ToList();
         return service;
 }
        public WalletError ChargeFeeOnSubscription(TradeSharpConnection ctx, SERVICE service, int usr, bool renewSubscription)
        {
            try
            {
                // создать платеж с кошелька usr на кошелек владельца сервиса (service)
                if (service.FixedPrice == 0)
                    return WalletError.OK; // все на шарку!
                var price = service.FixedPrice > 0
                                ? service.FixedPrice
                                : GetFeeByUserBalance(ctx, service);
                if (price == 0) return WalletError.OK;

                var usrWallet = ctx.WALLET.FirstOrDefault(w => w.User == usr);
                if (usrWallet == null)
                {
                    Logger.Error("ChargeFeeOnSubscription(usrId=" + usr + ") - wallet is not found");
                    return WalletError.ServerError;
                }

                if (HasUserPaidTheService(ctx, service, usr))
                    return WalletError.OK;

                // посчитать в валюте пользователя
                var usrAmount = price;
                if (usrWallet.Currency != service.Currency)
                {
                    string strError;
                    var targetAmount = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency(usrWallet.Currency, service.Currency,
                                                                           (double)usrAmount,
                                                                           QuoteStorage.Instance.ReceiveAllData(),
                                                                           out strError);
                    if (!targetAmount.HasValue)
                    {
                        Logger.ErrorFormat("ChargeFeeOnSubscription(usrId={0}) - currency rate is not found ({1}/{2})",
                            usr, usrWallet.Currency, service.Currency);
                        return WalletError.CurrencyExchangeFailed;
                    }
                    usrAmount = targetAmount.Value;
                }

                // если объем превышает возможности пользователя...
                if (usrWallet.Balance < usrAmount)
                {
                    Logger.InfoFormat("ChargeFeeOnSubscription(usrId={0}) - not enough money ({1}, needed {2})",
                            usr, usrAmount, usrWallet.Balance);
                    return WalletError.InsufficientFunds;
                }

                usrWallet.Balance -= usrAmount;
                var trans = ctx.TRANSFER.Add(new TRANSFER
                {
                    Amount = usrAmount,
                    TargetAmount = price,
                    Comment = "Fee on srv " + service.ID,
                    RefWallet = service.User,
                    User = usr,
                    ValueDate = DateTime.Now,
                    Subscription = service.ID
                });
                Logger.InfoFormat("Добавляется трансфер: usr={0}, comment={1}",
                    usr, trans.Comment);

                // добавить денег владельцу
                ctx.TRANSFER.Add(new TRANSFER
                {
                    Amount = price,
                    TargetAmount = usrAmount,
                    Comment = "Paid for srv " + service.ID,
                    RefWallet = usr,
                    User = service.User,
                    ValueDate = DateTime.Now,
                    Subscription = service.ID
                });
                var ownerWallet = ctx.WALLET.First(w => w.User == service.User);
                ownerWallet.Balance += price;

                // обновить подписку
                if (renewSubscription)
                {
                    var sub = ctx.SUBSCRIPTION.FirstOrDefault(s => s.Service == service.ID);
                    if (sub != null && sub.RenewAuto)
                    {
                        sub.TimeStarted = DateTime.Now.Date;
                        sub.TimeEnd = sub.TimeStarted.AddDays(1);
                    }
                }

                Logger.InfoFormat("ChargeFeeOnSubscription() - сохранение");
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Logger.Error("Error in ChargeFeeOnSubscription()", ex);
                return WalletError.ServerError;
            }
            return WalletError.OK;
        }
 public static void InitializeFake(TradeSharpConnection connection)
 {
     fakeDbConnection = connection;
 }
        public RequestStatus SubscribeUserOnPortfolio(
            TradeSharpConnection ctx,
            string subscriberLogin,
            TopPortfolio portfolio,
            decimal? maxFee,
            AutoTradeSettings tradeAutoSettings)
        {
            var user = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == subscriberLogin);
            if (user == null)
                return RequestStatus.Unauthorized;

            TOP_PORTFOLIO targetPortfolio = null;
            if (portfolio.Id > 0)
                targetPortfolio = ctx.TOP_PORTFOLIO.FirstOrDefault(p => p.Id == portfolio.Id);
            if (targetPortfolio != null)
                portfolio.ManagedAccount = targetPortfolio.ManagedAccount;

            // если портфель - пользовательский - сохранить его
            // для пользователя или обновить его имеющийся портфель
            if (!portfolio.IsCompanyPortfolio)
            {
                Logger.Info("SubscribeOnPortfolio() - user portfolio");
                try
                {
                    var existPortfolio = ctx.TOP_PORTFOLIO.FirstOrDefault(p => p.OwnerUser == user.ID);
                    if (existPortfolio != null)
                    {
                        if (!LinqToEntity.DecoratePortfolio(existPortfolio).AreSame(portfolio))
                        {
                            // удалить старый портфель пользователя
                            ctx.TOP_PORTFOLIO.Remove(existPortfolio);
                            existPortfolio = null;
                        }
                        else
                            targetPortfolio = existPortfolio;
                    }
                    // создать портфель пользователя
                    if (existPortfolio == null)
                    {
                        targetPortfolio = LinqToEntity.UndecoratePortfolio(portfolio);
                        targetPortfolio.OwnerUser = user.ID;
                        targetPortfolio.ManagedAccount = null;
                        ctx.TOP_PORTFOLIO.Add(targetPortfolio);
                        ctx.SaveChanges();
                    }
                }
                catch (DbEntityValidationException dbEx)
                {
                    Logger.Error("SubscribeUserOnPortfolio - ошибка сохранения портфеля");
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                    {
                        foreach (var validationError in validationErrors.ValidationErrors)
                        {
                            Logger.ErrorFormat("Свойство: {0}, ошибка: {1}",
                                validationError.PropertyName, validationError.ErrorMessage);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Ошибка в SubscribeOnPortfolio() - обновление портфеля", ex);
                    return RequestStatus.ServerError;
                }
            }
            else
            {// портфель компании
                Logger.Info("SubscribeOnPortfolio() - company portfolio");
                if (targetPortfolio == null)
                {
                    Logger.Error("Пользователь запросил несуществующий портфель компании " + portfolio.Id);
                    return RequestStatus.ServerError;
                }
            }

            // очистить подписки пользователя на портфели
            // и привязать его к целевому портфелю
            //Logger.Info("SubscribeOnPortfolio() - removing bindings");
            var oldBinding = ctx.USER_TOP_PORTFOLIO.FirstOrDefault(u => u.User == user.ID);
            // "посмотреть" настройки портфельной торговли в имеющейся подписке
            if (tradeAutoSettings == null)
            {
                if (oldBinding == null)
                {
                    Logger.ErrorFormat("Подписка пользователя {0} на портфель {1} - нет данных по автоматической торговле",
                        user.Login, portfolio.Id > 0 ? portfolio.Id.ToString() : portfolio.Name);
                    return RequestStatus.BadRequest;
                }
                tradeAutoSettings = new AutoTradeSettings
                {
                    FixedVolume = oldBinding.FixedVolume,
                    HedgingOrdersEnabled = oldBinding.HedgingOrdersEnabled,
                    MaxLeverage = oldBinding.MaxLeverage,
                    MaxVolume = oldBinding.MaxVolume,
                    MinVolume = oldBinding.MinVolume,
                    PercentLeverage = oldBinding.PercentLeverage ?? 100,
                    StepVolume = oldBinding.StepVolume,
                    TargetAccount = oldBinding.TargetAccount,
                    TradeAuto = oldBinding.AutoTrade ?? false,
                    VolumeRound = (VolumeRoundType?)oldBinding.VolumeRound
                };
            }

            if (oldBinding != null)
                ctx.USER_TOP_PORTFOLIO.Remove(oldBinding);

            //Logger.Info("SubscribeOnPortfolio() - adding binding");
            ctx.USER_TOP_PORTFOLIO.Add(new USER_TOP_PORTFOLIO
            {
                User = user.ID,
                Portfolio = targetPortfolio.Id,
                MaxFee = maxFee,
                AutoTrade = tradeAutoSettings.TradeAuto,
                MaxLeverage = tradeAutoSettings.MaxLeverage,
                PercentLeverage = tradeAutoSettings.PercentLeverage,
                HedgingOrdersEnabled = tradeAutoSettings.HedgingOrdersEnabled,
                FixedVolume = tradeAutoSettings.FixedVolume,
                MinVolume = tradeAutoSettings.MinVolume,
                MaxVolume = tradeAutoSettings.MaxVolume,
                VolumeRound = (int?)tradeAutoSettings.VolumeRound,
                StepVolume = tradeAutoSettings.StepVolume,
                TargetAccount = tradeAutoSettings.TargetAccount
            });
            ctx.SaveChanges();
            //Logger.Info("SubscribeOnPortfolio() - changes are saved");

            // найти трейдеров, удовлетворяющих критерию
            List<PerformerStat> performers;
            try
            {
                try
                {
                    performers = TradeSharpAccountStatistics.Instance.proxy.GetAllPerformersWithCriteria(true,
                        targetPortfolio.Criteria, targetPortfolio.ParticipantCount,
                        !targetPortfolio.DescendingOrder, (float?)targetPortfolio.MarginValue, 0);
                }
                catch (Exception ex)
                {
                    Logger.Error(
                        "Ошибка в SubscribeOnPortfolio() - получение перформеров (" + targetPortfolio.Criteria + ")",
                        ex);
                    return RequestStatus.ServerError;
                }

                if (performers == null)
                {
                    Logger.Error("Ошибка в SubscribeOnPortfolio() - список перформеров не получен (" + targetPortfolio.Criteria + ")");
                    return RequestStatus.ServerError;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в SubscribeOnPortfolio() - подписка", ex);
                return RequestStatus.ServerError;
            }

            // сравнить полученный список с текущими подписками заказчика ("инвестора")
            // сформировать список для "отписки" и список для подписки
            var performerAcs = performers.Select(p => p.Account).ToList();
            var subsToRemove = ctx.SUBSCRIPTION.Where(s => s.User == user.ID &&
                s.SERVICE1.ServiceType == (int)PaidServiceType.Signals &&
                !performerAcs.Contains(s.SERVICE1.AccountId ?? 0)).ToList();

            foreach (var sub in subsToRemove)
            {
                WalletError error;
                SubscribeOnService(ctx, user.ID, sub.Service, false, true, tradeAutoSettings, out error);
                if (error != WalletError.OK)
                {
                    Logger.ErrorFormat("Portfolio - unsubscribe user {0} from srv {1}: error {2}",
                        user.ID, sub.Service, error);
                }
            }

            // новоподписавшиеся
            foreach (var pf in performers)
            {
                WalletError error;
                SubscribeOnService(ctx, user.ID, pf.Service, true, false, tradeAutoSettings, out error);
                if (error != WalletError.OK)
                {
                    Logger.DebugFormat("Подписка SubscribeOnPortfolio({0}), сигн. {1}: {2}",
                        subscriberLogin, pf.Service, error);
                }
            }
            return RequestStatus.OK;
        }
Beispiel #22
0
        private RequestStatus GetUserSubscribedCats(TradeSharpConnection ctx,
            string userLogin, string hash, long localTime,
            out List<Subscription> categories)
        {
            categories = new List<Subscription>();
            try
            {
                var user = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == userLogin);
                if (user == null)
                    return RequestStatus.Unauthorized;

                var userHash = CredentialsHash.MakeCredentialsHash(userLogin, user.Password, localTime);
                if (userHash != hash)
                    return RequestStatus.Unauthorized;

                // получить подписку на торг. сигналы и собственные сигналы пользователя
                categories = (from uc in ctx.SUBSCRIPTION_V
                              where uc.User == user.ID
                              select uc).ToList().Select(LinqToEntity.DecorateSubscription).ToList();
                return RequestStatus.OK;
            }
            catch (Exception ex)
            {
                Logger.Error("Error in GetUserSubscribedCats()", ex);
                return RequestStatus.ServerError;
            }
        }
        public bool SubscribeOnService(TradeSharpConnection ctx,
            int userId, int serviceId, bool renewAuto, bool unsubscribe,
            AutoTradeSettings tradeSets, out WalletError error)
        {
            // имеющаяся подписка
            var subs = ctx.SUBSCRIPTION.FirstOrDefault(s => s.Service == serviceId && s.User == userId);

            // просто отписаться от сервиса
            if (unsubscribe)
            {
                error = WalletError.OK;
                if (subs == null)
                    return true;
                ctx.SUBSCRIPTION.Remove(subs);
                try
                {
                    ctx.SaveChanges();
                }
                catch (Exception ex)
                {
                    Logger.Error("Ошибка удаления подписки (SubscribeOnService)", ex);
                    error = WalletError.ServerError;
                    return false;
                }

                return true;
            }

            var paidService = ctx.SERVICE.FirstOrDefault(s => s.ID == serviceId);
            if (paidService == null)
            {
                error = WalletError.InvalidData;
                return false;
            }

            // проверить - не подписывается ли пользователь сам на себя?
            if (paidService.User == userId)
            {
                error = WalletError.InvalidData;
                return false;
            }

            // провести списание денежных средств
            // содрать денежку
            var feeError = ChargeFeeOnSubscription(ctx, serviceId, userId, false);
            if (feeError != WalletError.OK)
            {
                error = feeError;
                return false;
            }

            // продлить или обновить подписку
            var subExists = subs != null;
            if (subs == null)
                subs = new SUBSCRIPTION();
            subs.RenewAuto = renewAuto;
            subs.TimeEnd = DateTime.Now.Date.AddDays(1);
            subs.TimeStarted = DateTime.Now.Date;
            subs.User = userId;
            subs.Service = serviceId;
            if (!subExists)
                ctx.SUBSCRIPTION.Add(subs);

            // обновить или создать настройки торговли
            var signalTradeSets = ctx.SUBSCRIPTION_SIGNAL.FirstOrDefault(s => s.Service == serviceId && s.User == userId);
            var setsExists = signalTradeSets != null;
            if (signalTradeSets == null)
                signalTradeSets = new SUBSCRIPTION_SIGNAL();
            signalTradeSets.AutoTrade = tradeSets.TradeAuto;
            signalTradeSets.FixedVolume = tradeSets.FixedVolume;
            signalTradeSets.HedgingOrdersEnabled = tradeSets.HedgingOrdersEnabled;
            signalTradeSets.MaxLeverage = tradeSets.MaxLeverage;
            signalTradeSets.MaxVolume = tradeSets.MaxVolume;
            signalTradeSets.MinVolume = tradeSets.MinVolume;
            signalTradeSets.PercentLeverage = tradeSets.PercentLeverage;
            signalTradeSets.Service = serviceId;
            signalTradeSets.StepVolume = tradeSets.StepVolume;
            signalTradeSets.User = userId;
            signalTradeSets.TargetAccount = tradeSets.TargetAccount;
            signalTradeSets.VolumeRound = (int?)tradeSets.VolumeRound;
            if (!setsExists)
                ctx.SUBSCRIPTION_SIGNAL.Add(signalTradeSets);

            try
            {
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка сохранения подписки (SubscribeOnService)", ex);
                error = WalletError.ServerError;
                return false;
            }

            error = WalletError.OK;
            return true;
        }
 public bool HasUserPaidTheService(TradeSharpConnection ctx, SERVICE service, int usr)
 {
     var nowDate = DateTime.Now.Date;
     // проверить - совершался ли платеж за подключение к подписке в ближайшие N минут?
     // если да - не снимать денег
     var hasTodayTransfers = ctx.TRANSFER.Any(t => t.User == usr &&
         EntityFunctions.TruncateTime(t.ValueDate) == nowDate && t.Subscription == service.ID);
     return hasTodayTransfers;
 }
Beispiel #25
0
 private bool ModifyClosedPosition(MarketOrder order, TradeSharpConnection ctx, POSITION_CLOSED pos,
     out string errorString)
 {
     errorString = string.Empty;
     if (order.IsClosed)
     {
         var opened = new POSITION
         {
             AccountID = pos.AccountID,
             ID = pos.ID,
             Comment = order.Comment,
             Magic = order.Magic,
             ExpertComment = order.ExpertComment,
             PendingOrderID = order.PendingOrderID,
             PriceBest = (decimal?)order.PriceBest,
             PriceEnter = (decimal)order.PriceEnter,
             PriceWorst = (decimal?)order.PriceWorst,
             Side = order.Side,
             Stoploss = (decimal?)order.StopLoss,
             Symbol = order.Symbol,
             Takeprofit = (decimal?)order.TakeProfit,
             TimeEnter = order.TimeEnter,
             Volume = order.Volume,
             State = (int) order.State,
             MasterOrder = order.MasterOrder
         };
         ctx.POSITION_CLOSED.Remove(pos);
         ctx.POSITION.Add(opened);
         ctx.SaveChanges();
         Logger.InfoFormat("Closed order {0} {1} {2} {3} was reopened",
             pos.ID, pos.Side > 0 ? "BUY" : "SELL", pos.Volume, pos.Symbol);
         return true;
     }
     pos.Comment = order.Comment;
     pos.Magic = order.Magic;
     pos.ExpertComment = order.ExpertComment;
     pos.PendingOrderID = order.PendingOrderID;
     pos.PriceBest = (decimal?)order.PriceBest;
     pos.PriceEnter = (decimal)order.PriceEnter;
     pos.PriceWorst = (decimal?)order.PriceWorst;
     pos.Side = order.Side;
     pos.Stoploss = (decimal?)order.StopLoss;
     pos.Symbol = order.Symbol;
     pos.Takeprofit = (decimal?)order.TakeProfit;
     if (order.TimeEnter != default(DateTime))
         pos.TimeEnter = order.TimeEnter;
     pos.Volume = order.Volume;
     pos.ExitReason = (int) order.ExitReason;
     pos.PriceExit = (decimal) (order.PriceExit ?? 0);
     pos.PriceWorst = (decimal?) order.PriceWorst;
     pos.ResultBase = (decimal)order.ResultBase;
     pos.ResultDepo = (decimal)order.ResultDepo;
     pos.ResultPoints = (decimal)order.ResultPoints;
     pos.TimeExit = order.TimeExit ?? default(DateTime);
     pos.Swap = (decimal) (order.Swap ?? 0);
     Logger.InfoFormat("Closed order {0} {1} {2} {3} was modified",
             pos.ID, pos.Side > 0 ? "BUY" : "SELL", pos.Volume, pos.Symbol);
     ctx.SaveChanges();
     return true;
 }
Beispiel #26
0
        private void DoFixtransactions(BackgroundWorkerTask taskParam)
        {
            var accountList = (List<int>) taskParam.DataParam;
            int accountNumber = 0;
            foreach (var id in accountList)
            {
                if (workerQuote.CancellationPending) break;
                var accountId = id;
                using (var db = new TradeSharpConnection())
                {
                    foreach (var order in db.POSITION_CLOSED.Where(p => p.AccountID == accountId))
                    {
                        if (workerQuote.CancellationPending) break;
                        var orderId = order.ID;
                        if (db.BALANCE_CHANGE.Any(bc => bc.Position == orderId)) continue;

                        var changeType = (int) (order.ResultDepo > 0 ? BalanceChangeType.Profit : BalanceChangeType.Loss);
                        var closeTime = order.TimeExit;
                        var orderResult = Math.Abs(order.ResultDepo);
                        var missIdBc = db.BALANCE_CHANGE.FirstOrDefault(b => b.AccountID == accountId &&
                                                                             b.ValueDate == closeTime &&
                                                                             b.Amount == orderResult);
                        if (missIdBc != null)
                        {
                            missIdBc.Position = orderId;
                            missIdBc.ChangeType = changeType;
                        }
                        else
                            db.BALANCE_CHANGE.Add(new BALANCE_CHANGE
                            {
                                AccountID = order.AccountID,
                                Position = order.ID,
                                Amount = order.ResultDepo,
                                ChangeType = changeType,
                                ValueDate = order.TimeExit
                            });
                    }
                    db.SaveChanges();
                }
                workerQuote.ReportProgress(100*(accountNumber++)/accountList.Count);
            }
        }
        public RequestStatus UnsubscribeUserFromPortfolio(TradeSharpConnection ctx, string subscriberLogin,
            bool deletePortfolio, bool deleteSubscriptions)
        {
            try
            {
                var user = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == subscriberLogin);
                if (user == null)
                    return RequestStatus.Unauthorized;

                var subscriptions = ctx.USER_TOP_PORTFOLIO.Where(u => u.User == user.ID).ToList();
                foreach (var portfolioSub in subscriptions)
                {
                    // удалить подписку
                    ctx.USER_TOP_PORTFOLIO.Remove(portfolioSub);
                    Logger.InfoFormat("UnsubscribeUserFromPortfolio({0}) - отписан от портфеля", subscriberLogin);

                    // если подписка была на пользовательский портфель - удалить пользовательский портфель
                    if (deletePortfolio)
                    {
                        var portfolio = ctx.TOP_PORTFOLIO.Single(p => p.Id == portfolioSub.Portfolio);
                        if (portfolio.OwnerUser == user.ID)
                            ctx.TOP_PORTFOLIO.Remove(portfolio);
                    }

                    if (!deleteSubscriptions) continue;

                    // удалить подписки на сервисы
                    var subs = ctx.SUBSCRIPTION.Where(s => s.User == user.ID).ToList();
                    foreach (var sub in subs)
                        ctx.SUBSCRIPTION.Remove(sub);
                }
                ctx.SaveChanges();

                return RequestStatus.OK;
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в UnsubscribePortfolio()", ex);
                return RequestStatus.ServerError;
            }
        }
Beispiel #28
0
        /// <summary>
        /// возвращает - соклько раз была списана комиссия
        /// </summary>
        public int ReCalculateAccountShares(TradeSharpConnection ctx, SERVICE srv)
        {
            var feeTakenCount = 0;
            try
            {
                PaidService serviceWithFeeScale = null;

                // дольки
                var shares =
                    ctx.ACCOUNT_SHARE.Where(s => s.Account == srv.AccountId && s.ShareOwner != srv.User).ToList();
                if (shares.Count == 0) return feeTakenCount;

                var ownerShare =
                    ctx.ACCOUNT_SHARE.FirstOrDefault(s => s.Account == srv.AccountId && s.ShareOwner == srv.User);
                if (ownerShare == null)
                {
                    Logger.ErrorFormat(
                        "ReCalculateAccountShares(service={0}, account={1}, owner={2}) - доля владельца не найдена",
                        srv.ID, srv.AccountId, srv.User);
                    return feeTakenCount;
                }

                var account = ctx.ACCOUNT.First(a => a.ID == srv.AccountId);

                // получить актуальный баланс (средства) счета
                var positions =
                    ctx.POSITION.Where(p => p.AccountID == srv.AccountId && p.State == (int) PositionState.Opened)
                       .ToList().Select(LinqToEntity.DecorateOrder).ToList();

                var quotes = QuoteStorage.Instance.ReceiveAllData();

                bool noQuoteError;
                var profit = DalSpot.Instance.CalculateOpenedPositionsCurrentResult(positions,
                                                                                    quotes, account.Currency,
                                                                                    out noQuoteError);
                var equity = account.Balance + (decimal) profit;
                if (noQuoteError)
                {
                    Logger.Error("Ошибка в ReCalculateAccountShares - нет котировки для пересчета одного из тикеров (" +
                                 string.Join(", ", positions.Select(p => p.Symbol).Distinct()));
                    return feeTakenCount;
                }

                // пересчитать долю каждого пайщика
                var ownersMoney = equity * ownerShare.Share / 100M;
                serviceWithFeeScale = GetPaidServiceProgressiveFeeScaleDetail(ctx, srv);

                foreach (var share in shares)
                {
                    bool feeWasTaken;
                    var record = CalculateAccountShare(ctx, share, ownerShare,
                                                       ref ownersMoney, equity, serviceWithFeeScale, out feeWasTaken);
                    ctx.ACCOUNT_SHARE_HISTORY.Add(record);
                    if (feeWasTaken)
                        feeTakenCount++;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в ReCalculateAccountShares", ex);
            }

            return feeTakenCount;
        }
 //, PLATFORM_USER usr)
 /// <summary>
 /// по средствам клиента определить сумму по прогрессивной шкале
 /// </summary>
 private decimal GetFeeByUserBalance(TradeSharpConnection ctx, SERVICE srv)
 {
     var rate = ctx.SERVICE_RATE.FirstOrDefault(r => r.Service == srv.ID);
     return rate == null ? 0 : rate.Amount;
 }
        /// <summary>
        /// отключить подписчика
        /// заодно отрубить ему торговые сигналы
        /// </summary>
        public bool UnsubscribeSubscriber(TradeSharpConnection ctx, SUBSCRIPTION sub)
        {
            // отписать подписчика и сформировать для него уведомление
            try
            {
                var service = ctx.SERVICE.First(s => s.ID == sub.Service);
                Logger.InfoFormat("UnsubscribeSubscriber(srv={0}, user={1}, srvAccount={2})",
                    sub.Service, sub.User, service.AccountId);

                // отписать от торг. сигналов?
                if (service.ServiceType == (int)PaidServiceType.Signals)
                {
                    var signalService = (from srv in ctx.SERVICE
                                         where srv.ID == sub.Service
                                         select srv).FirstOrDefault();

                    if (signalService != null)
                    {
                        var signalId = signalService.ID;
                        var query = (from us in ctx.SUBSCRIPTION
                                     where us.Service == signalId
                                        && us.User == sub.User
                                     select us);

                        var userSignalToRemove = new List<SUBSCRIPTION>();
                        foreach (var userSubscribed in query)
                            userSignalToRemove.Add(userSubscribed);
                        Logger.InfoFormat("UnsubscribeSubscriber(): remove {0} signals", userSignalToRemove.Count);

                        foreach (var userSubscribed in userSignalToRemove)
                            ctx.SUBSCRIPTION.Remove(userSubscribed);
                    }
                    else
                    {
                        Logger.ErrorFormat("UnsubscribeSubscriber(#{0}) - владелец сигнала #{1} не найден",
                            sub.User, sub.Service);
                    }
                }

                // убрать саму подписку
                ctx.SUBSCRIPTION.Remove(sub);
                // !! с уведомлением пока что вопрос

                return true;
            }
            catch (Exception ex)
            {
                Logger.Error("Error in UnsubscribeSubscriber()", ex);
                return false;
            }
        }
Beispiel #31
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;
        }