public RequestStatus ChangeBalance(int accountId, decimal summ, string comment, DateTime date, BalanceChangeType changeType)
        {
            if (summ == 0) return RequestStatus.BadRequest;
            // корректировать знак
            summ = BalanceChange.CorrectSign(summ, changeType);

            try
            {
                using (var ctx = DatabaseContext.Instance.Make())
                {
                    ACCOUNT acc;
                    try
                    {
                        acc = (from a in ctx.ACCOUNT
                               where a.ID == accountId
                               select a).First();
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("Ошибка получения счета для редактирования {0}: {1}", accountId, ex);
                        return RequestStatus.ServerError;
                    }

                    var bc = new BALANCE_CHANGE
                    {
                        AccountID = accountId,
                        ValueDate = date,
                        Amount = summ,
                        ChangeType = (int)changeType,
                        Description = comment
                    };
                    try
                    {
                        acc.Balance = acc.Balance + summ;
                        ctx.BALANCE_CHANGE.Add(bc);
                        ctx.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("Ошибка изменения баланса счета {0}: {1}", accountId, ex);
                        return RequestStatus.ServerError;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в ChangeBalance", ex);
                return RequestStatus.ServerError;
            }
            return RequestStatus.OK;
        }
 public static BalanceChange DecorateBalanceChange(BALANCE_CHANGE bc)
 {
     return(new BalanceChange
     {
         AccountID = bc.AccountID,
         Amount = bc.Amount,
         ChangeType = (BalanceChangeType)bc.ChangeType,
         CurrencyToDepoRate = 1,
         Description = bc.Description,
         ID = bc.ID,
         ValueDate = bc.ValueDate,
         PositionId = bc.Position
     });
 }
        private BALANCE_CHANGE MakeSwapTransfer(decimal amountCounter, string ticker, string curxDepo, 
            Dictionary<string, QuoteData> quotes,
            int posId, int accountId, DateTime nowTime)
        {
            var amountDepo = amountCounter;
            bool inverse, equalPairs;
            var symbol = DalSpot.Instance.FindSymbol(ticker, false, curxDepo, out inverse, out equalPairs);
            if (!equalPairs)
            {
                if (string.IsNullOrEmpty(symbol))
                {
                    Logger.Error("MakeSwapTransfer - не найден тикер пересчета " + ticker + " в " + curxDepo);
                    return null;
                }

                QuoteData quote;
                if (!quotes.TryGetValue(symbol, out quote))
                {
                    Logger.ErrorFormat("Начисление свопа поз. {0} ({1}) - нет котировки {2}",
                        posId, ticker, symbol);
                    return null;
                }
                var price = inverse
                                    ? (amountDepo < 0 ? 1 / quote.bid : 1 / quote.ask)
                                    : (amountDepo < 0 ? quote.ask : quote.bid);
                amountDepo *= (decimal)price;
            }

            var transfer = new BALANCE_CHANGE
                {
                    Amount = amountDepo,
                    AccountID = accountId,
                    ChangeType = (int)BalanceChangeType.Swap,
                    ValueDate = nowTime,
                    Description = "swap " + posId,
                    Position = posId
                };
            return transfer;
        }
        public ActionResult ChangeBalance(BalanceChangeRequest bc)
        {
            Logger.InfoFormat("Начинаем пополнять счёт {0}", bc.AccountId);
            var errors = new List<string>();
            if (bc.Amount <= 0)
                errors.Add(Resource.ErrorMessageAmountMustBePositive);
            var date = bc.ValueDate.ToDateTimeUniformSafe();
            if (!date.HasValue)
                errors.Add(string.Format("{0} {1}", Resource.ErrorMessageUnableParseDateTime, Resource.TextExampleCorrectFillDateTime));

            if (!string.IsNullOrEmpty(bc.Description) && bc.Description.Length > 60)
                bc.Description = bc.Description.Substring(0, 60);

            if (errors.Count > 0)
            {
                Logger.Error(string.Format("Не удалось пополнить счет {0}", bc.AccountId) + string.Join(", ", errors));
                return Json(new
                    {
                        status = false,
                        errorString = Resource.ErrorMessage + ": " + string.Join(", ", errors)
                    }, JsonRequestBehavior.AllowGet);}

            try
            {
                using (var ctx = DatabaseContext.Instance.Make())
                {
                    var bal = new BALANCE_CHANGE
                        {
                            AccountID = bc.AccountId,
                            Amount = (decimal)bc.Amount,
                            // ReSharper disable PossibleInvalidOperationException
                            ChangeType = (int)bc.ChangeType,
                            // ReSharper restore PossibleInvalidOperationException
                            ValueDate = date.Value,
                            Description = bc.Description
                        };
                    ctx.BALANCE_CHANGE.Add(bal);
                    var account = ctx.ACCOUNT.First(a => a.ID == bc.AccountId);
                    account.Balance +=
                        new BalanceChange
                            {
                                ChangeType = bc.ChangeType,
                                Amount = (decimal)bc.Amount,
                                CurrencyToDepoRate = 1
                            }.SignedAmountDepo;
                    ctx.SaveChanges();
                }

                Logger.InfoFormat("Счёт {0} пополнен", bc.AccountId);
                return Json(new
                {
                    status = true,
                    errorString = ""
                }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("Не удалось пополнить счет {0}", bc.AccountId) + string.Join(", ", errors));
                return Json(new
                {
                    status = false,
                    errorString = Resource.ErrorMessage + ": " + ex.Message
                }, JsonRequestBehavior.AllowGet);
            }
        }
        private string CreateAccount(out int accountId)
        {
            accountId = -1;
            if (string.IsNullOrEmpty(tbLogin.Text) ||
                string.IsNullOrEmpty(tbEmail.Text) ||
                string.IsNullOrEmpty(tbPassword.Text) ||
                cbAccountGroup.SelectedIndex < 0) return "Поля не заполнены";

            var login = tbLogin.Text;
            var password = tbPassword.Text;
            var email = tbEmail.Text;
            var group = cbAccountGroup.SelectedItem.ToString();
            var depo = tbStartDepo.Text.ToDecimalUniformSafe() ?? 0;
            var createTime = dpCreateTime.Value;

            using (var conn = DatabaseContext.Instance.Make())
            {
                if (conn.PLATFORM_USER.Any(u => u.Login == login))
                    return "Логин занят";
                if (conn.PLATFORM_USER.Any(u => u.Email == email))
                    return "Email занят";

                try
                {
                    var usr = new PLATFORM_USER
                    {
                        Login = login,
                        Password = password,
                        Email = email,
                        Name = tbName.Text,
                        Surname = tbSurname.Text,
                        RegistrationDate = createTime,
                        RoleMask = 0,
                        Patronym = "Н",
                        Title = "-"
                    };
                    conn.PLATFORM_USER.Add(usr);
                    var account = new ACCOUNT
                    {
                        Currency = "USD",
                        Balance = depo,
                        MaxLeverage = tbMaxLeverage.Text.ToDecimalUniformSafe() ?? 100,
                        AccountGroup = group,
                        TimeCreated = createTime,
                        Status = (int) Account.AccountStatus.Created
                    };
                    conn.ACCOUNT.Add(account);
                    conn.SaveChanges();
                    var pa = new PLATFORM_USER_ACCOUNT
                    {
                        PlatformUser = usr.ID,
                        Account = account.ID,
                        RightsMask = 0
                    };
                    conn.PLATFORM_USER_ACCOUNT.Add(pa);

                    var bc = new BALANCE_CHANGE
                    {
                        AccountID = account.ID,
                        Amount = depo,
                        ChangeType = (int) BalanceChangeType.Deposit,
                        Description = "Initial deposit",
                        ValueDate = createTime
                    };
                    conn.BALANCE_CHANGE.Add(bc);
                    conn.SaveChanges();
                    accountId = account.ID;
                    return string.Empty;
                }
                catch (Exception ex)
                {
                    return ex.GetType().Name + ": " + ex.Message;
                }
            }
        }
 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;
     }
 }
        /// <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();
        }
        /// <summary>
        /// Закрытие сделок
        /// </summary>
        /// <param name="strId">Уникальные идентификаторы закрываемых сделок, перечисленные через запятую</param>
        /// <param name="timeExit">Время выхода</param>
        /// <param name="exitReason">Symbol, Side (в виде Ask и Bid), Price</param>
        /// <param name="lstPrice">Причина закрытия сделки, указанная пользователем</param>
        public List<string> ClosingPositions(string strId, DateTime timeExit, PositionExitReason exitReason, List<Tuple<string, int, float>> lstPrice)
        {
            Logger.Info("Начинаем закрывать сделки " + strId);

            var result = new List<string>();
            var id = strId.ToIntArrayUniform();
            try
            {
                using (var ctx = DatabaseContext.Instance.Make())
                {
                    // Вытаскиваем все открытые сделки, которые нужно закрыть
                    var selOrders = new List<MarketOrder>();
                    // ReSharper disable LoopCanBeConvertedToQuery
                    foreach (var order in ctx.POSITION.Where(x => id.Contains(x.ID))) selOrders.Add(LinqToEntity.DecorateOrder(order));
                    // ReSharper restore LoopCanBeConvertedToQuery

                    if (selOrders.Count != id.Length)
                        Logger.Error("ClosingPositions() - в таблице 'POSITION' не найдены некоторые или все сделки с идентификаторами " + strId);

                    // Группируем все сделки по счётам
                    var selOrderGroupByAccount = selOrders.GroupBy(x => x.AccountID);

                    // Перебираем все счета
                    foreach (var orderGroup in selOrderGroupByAccount)
                    {
                        // Список удачно закрытых сделок в текущем счёте
                        var successClosedPositions = new List<string>();

                        var acc = accountRepository.GetAccount(orderGroup.Key);
                        if (acc == null)
                        {
                            Logger.Error("ClosingPositions() - не удалось получить счёт " + orderGroup.Key);
                            continue;
                        }

                        Logger.Info("Начинаем закрывать сделки в счёте " + orderGroup.Key);
                        // Перебираем все сделки в текущем счёте
                        foreach (var order in orderGroup)
                        {
                            #region
                            //Ищем цену выхода, указанную пользователем, для сделок с таким тикером и направлением
                            var priceExitTuple = lstPrice.FirstOrDefault(x => x.Item1 == order.Symbol && x.Item2 == order.Side);

                            if (priceExitTuple == null)
                            {
                                Logger.Error(string.Format("ClosingPositions() - не найдена цена выхода, указанная пользователем, для сделок счёта {0} с тикером {1} и направлением {2}",
                                    order.ID, order.Symbol, order.Side)); continue;
                            }

                            var closedOrder = order.MakeCopy();
                            closedOrder.State = PositionState.Closed;
                            closedOrder.TimeExit = timeExit;
                            closedOrder.PriceExit = priceExitTuple.Item3;
                            closedOrder.ExitReason = exitReason;

                            // посчитать прибыль
                            string errorStr;
                            if (!DealProfitCalculator.CalculateOrderProfit(closedOrder, acc.Currency, priceExitTuple.Item3, out errorStr))
                            {
                                if (!string.IsNullOrEmpty(errorStr))
                                    Logger.Error("Сделка " + closedOrder.ID +  " не будет закрыта - не удалось пересчитать прибыль : " + errorStr);
                                continue;
                            }

                            var balance = new BALANCE_CHANGE
                                {
                                    AccountID = order.AccountID,
                                    ChangeType = closedOrder.ResultBase > 0 ? (int)BalanceChangeType.Profit : (int)BalanceChangeType.Loss,
                                    Description = string.Format("результат сделки #{0}", order.ID),
                                    Amount = (decimal)Math.Abs(closedOrder.ResultDepo),
                                    ValueDate = closedOrder.TimeExit.Value
                                };

                            // убрать сделку из числа открытых, добавить закрытую и добавить проводку по счету
                            try
                            {
                                // убрать
                                var pos = ctx.POSITION.FirstOrDefault(p => p.ID == order.ID);
                                ctx.POSITION.Remove(pos);
                                Logger.Info("запись о сделке " + order.ID + " удалена из таблици POSITION");

                                ctx.POSITION_CLOSED.Add(LinqToEntity.UndecorateClosedPosition(closedOrder));
                                Logger.Info("запись о сделке " + order.ID + " добавленав таблицу POSITION_CLOSED");

                                // добавить проводку по счету
                                ctx.BALANCE_CHANGE.Add(balance);
                                var acBase = ctx.ACCOUNT.FirstOrDefault(ac => ac.ID == order.AccountID);

                                if (acBase == null)
                                {
                                    Logger.Error("ClosingPositions() - не удалось найти счёт " + order.AccountID + " в таблице 'ACCOUNT', что бы добавить проводку");
                                    continue;
                                }

                                acBase.Balance += (decimal)closedOrder.ResultDepo;
                                Logger.Info("Баланс счёта " + order.AccountID + " изменён на величину " + (decimal)closedOrder.ResultDepo);
                            }
                            catch (Exception ex)
                            {
                                Logger.Error("ClosingPositions() - Ошибка при попытке убрать сделку из числа открытых, добавить закрытую и добавить проводку по счету", ex);
                                continue;
                            }
                            #endregion
                            successClosedPositions.Add(order.ID.ToString());
                            Logger.Error("Сделка " + order.ID + " отредактирована удачно");
                        }
                        ReCalculateAccountBalance(ctx, acc.ID);

                        Logger.Info("Начинаем сохранять в базу данных изменения по счёту " + orderGroup.Key);
                        ctx.SaveChanges();
                        result.AddRange(successClosedPositions);

                    }

                    if (result.Count == 0)
                        Logger.Info("Не удалось закрыть ни одной из указанных сделок");
                    else
                        Logger.Info("Изменения сохранены. Из указанных сделок " + strId + " закрыты следующие: " + string.Join(", ", result));
                }
            }
            catch (Exception ex)
            {
                Logger.Error("ClosingPositions() - возникла ошибка при попытке сохранить изменения в базу данных. Не удалось закрыть сделки " + strId, ex);
            }
            return result;
        }
        private ACCOUNT GetAccountData(int accountId, out List<BalanceChange> transfers)
        {
            if (testOnly)
            {
                transfers = new List<BalanceChange>
                {
                    new BalanceChange
                    {
                        AccountID = accountId,
                        Amount = startDepo,
                        ChangeType = BalanceChangeType.Deposit,
                        Currency = "USD",
                        ValueDate = startTime
                    }
                };

                return new ACCOUNT
                {
                    ID = accountId,
                    Balance = startDepo,
                    Currency = "USD",
                    AccountGroup = "Demo",
                    TimeCreated = startTime
                };
            }

            ACCOUNT accountData;
            try
            {
                using (var conn = DatabaseContext.Instance.Make())
                {
                    accountData = conn.ACCOUNT.First(a => a.ID == accountId);
                    transfers = conn.BALANCE_CHANGE.Where(bc =>
                        bc.AccountID == accountId).ToList().Select(LinqToEntity.DecorateBalanceChange).ToList();
                    if (transfers.Count == 0)
                    {
                        // добавить начальное пополнение счета
                        var firstBc = new BALANCE_CHANGE
                        {
                            AccountID = accountId,
                            ValueDate = accountData.TimeCreated,
                            ChangeType = (int) BalanceChangeType.Deposit,
                            Description = "initial depo",
                            Amount = startDepo
                        };
                        conn.BALANCE_CHANGE.Add(firstBc);
                        conn.SaveChanges();

                        var pa = conn.PLATFORM_USER_ACCOUNT.First(p => p.Account == accountId);

                        var trans = new TRANSFER
                        {
                            Amount = firstBc.Amount,
                            ValueDate = firstBc.ValueDate,
                            BalanceChange = firstBc.ID,
                            Comment = "initial depo",
                            TargetAmount = firstBc.Amount,
                            User = pa.PlatformUser
                        };
                        conn.TRANSFER.Add(trans);
                        conn.SaveChanges();
                        transfers.Add(LinqToEntity.DecorateBalanceChange(firstBc));
                    }
                }
                return accountData;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("Error in GetAccountData({0}): {1}", accountId, ex);
                throw;
            }
        }
        private static void SaveTrackInDatabase(RobotContextBacktest context, int accountId, 
            List<BalanceChange> transfers,
            int transfersInDbCount)
        {
            try
            {
                Logger.InfoFormat("Сохранение изменений в БД для счета {0}", accountId);

                int nextPosId;
                using (var conn = DatabaseContext.Instance.Make())
                {
                    nextPosId = Math.Max(conn.POSITION.Max(p => p.ID), conn.POSITION_CLOSED.Max(p => p.ID)) + 1;
                }

                Logger.InfoFormat("Запись {0} позиций для счета {1}",
                    context.PosHistory.Count, accountId);

                // закрытые ордера
                var listPos = new List<POSITION_CLOSED>();
                foreach (var pos in context.PosHistory)
                {
                    var orderClosed = LinqToEntity.UndecorateClosedPosition(pos);
                    orderClosed.ID = ++nextPosId;
                    listPos.Add(orderClosed);
                }

                using (var conn = DatabaseContext.Instance.Make())
                {
                    conn.BulkInsert(listPos);
                    conn.SaveChanges();
                }

                // трансферы...
                var listTrans =
                    transfers.Skip(transfersInDbCount).Select(t =>
                        new BALANCE_CHANGE
                        {
                            AccountID = accountId,
                            Amount = t.Amount,
                            ChangeType = (int) t.ChangeType,
                            ValueDate = t.ValueDate,
                        }).ToList();
                // + трансферы по закрытым ордерам
                foreach (var pos in listPos)
                {
                    var transfer = new BALANCE_CHANGE
                    {
                        AccountID = accountId,
                        Amount = Math.Abs(pos.ResultDepo),
                        ChangeType = (int) (pos.ResultDepo >= 0
                            ? BalanceChangeType.Profit
                            : BalanceChangeType.Loss),
                        ValueDate = pos.TimeExit,
                        Position = pos.ID,
                    };
                    listTrans.Add(transfer);
                }

                using (var conn = DatabaseContext.Instance.Make())
                {
                    conn.BulkInsert(listTrans);
                    conn.SaveChanges();
                }

                // открытые сделки - как есть
                using (var conn = DatabaseContext.Instance.Make())
                {
                    foreach (var pos in context.Positions)
                    {
                        var orderOpened = LinqToEntity.UndecorateOpenedPosition(pos);
                        orderOpened.ID = ++nextPosId;
                        conn.POSITION.Add(orderOpened);
                    }

                    conn.SaveChanges();
                }
                Logger.InfoFormat("Сохранение успешно для счета {0}: {1} сделок сохранено",
                    accountId, context.PosHistory.Count + context.Positions.Count);
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка сохранения трека пользователя в БД", ex);
            }
        }
        public bool SetBalance(string hash, string userLogin, long localTime,
            int accountId, decimal newBalance, string comment, out string errorString)
        {
            errorString = string.Empty;
            try
            {
                using (var ctx = DatabaseContext.Instance.Make())
                {
                    var user = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == userLogin);
                    if (user == null)
                    {
                        errorString = "Unauthorised (not found)";
                        return false;
                    }

                    var userHash = CredentialsHash.MakeCredentialsHash(userLogin, user.Password, localTime);
                    if (userHash != hash)
                    {
                        errorString = "Unauthorised (wrong credentials)";
                        return false;
                    }

                    if (!PlatformUser.IsAdmin(user.RoleMask) &&
                        !PlatformUser.IsManager(user.RoleMask))
                    {
                        errorString = "Unauthorised (insufficient rights)";
                        return false;
                    }

                    var account = ctx.ACCOUNT.FirstOrDefault(a => a.ID == accountId);
                    if (account == null)
                    {
                        errorString = "Account " + accountId + " was not found";
                        return false;
                    }

                    var delta = newBalance - account.Balance;
                    if (delta == 0)
                        return true;

                    // сформировать транзакцию и поправить баланс
                    var sign = Math.Sign(delta);
                    var amount = Math.Abs(delta);
                    var trans = new BALANCE_CHANGE
                    {
                        AccountID = accountId,
                        ChangeType = sign > 0 ? (int) BalanceChangeType.Deposit : (int) BalanceChangeType.Withdrawal,
                        Amount = amount,
                        ValueDate = DateTime.Now,
                        Description = comment
                    };
                    account.Balance = newBalance;
                    ctx.BALANCE_CHANGE.Add(trans);
                    ctx.SaveChanges();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Ошибка в SetBalance()", ex);
            }
            return false;
        }
 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);
 }
        public static List<string> CorrectBalance(List<int> actIds, int minAmount, int maxAmount, int maxDelta)
        {
            var rand = new Random();
            var messages = new List<string>();
            foreach (var acId in actIds)
            {
                var accountId = acId;
                var targetAmount = rand.Next(minAmount, maxAmount);
                using (var conn = DatabaseContext.Instance.Make())
                {
                    var sumDeltaBalance = conn.BALANCE_CHANGE.Where(b => b.AccountID == accountId).Sum(b =>
                        (b.ChangeType == (int)BalanceChangeType.Loss ||
                         b.ChangeType == (int)BalanceChangeType.Withdrawal)
                            ? -b.Amount
                            : b.Amount);
                    var accountBalance = conn.ACCOUNT.Where(a => a.ID == accountId).Select(a => a.Balance).First();
                    if (accountBalance != sumDeltaBalance)
                    {
                        var acc = conn.ACCOUNT.First(a => a.ID == accountId);
                        acc.Balance = sumDeltaBalance;
                    }

                    var delta = Math.Abs(targetAmount - sumDeltaBalance);
                    if (delta > maxDelta)
                    {
                        // пополнить - вывести
                        var amount = targetAmount - sumDeltaBalance;
                        var bc = new BALANCE_CHANGE
                        {
                            AccountID = accountId,
                            ChangeType =
                                amount > 0 ? (int)BalanceChangeType.Deposit : (int)BalanceChangeType.Withdrawal,
                            Description = amount > 0 ? "rebalance (depo)" : "rebalance (wdth)",
                            ValueDate = DateTime.Now,
                            Amount = delta
                        };
                        conn.BALANCE_CHANGE.Add(bc);
                        conn.SaveChanges();

                        var ownerId = (from pa in conn.PLATFORM_USER_ACCOUNT
                                       join a in conn.ACCOUNT on pa.Account equals a.ID
                                       select pa.PlatformUser).First();

                        // проводка
                        var trans = new TRANSFER
                        {
                            Amount = delta,
                            ValueDate = DateTime.Now,
                            TargetAmount = delta,
                            BalanceChange = bc.ID,
                            Comment = bc.Description,
                            User = ownerId
                        };
                        conn.TRANSFER.Add(trans);

                        messages.Add(string.Format("#{0}: {1} -> {2} USD",
                            accountId, sumDeltaBalance.ToStringUniformMoneyFormat(),
                            targetAmount.ToStringUniformMoneyFormat()));
                    }
                    else
                    {
                        messages.Add(string.Format("#{0}: {1} USD",
                            accountId, sumDeltaBalance.ToStringUniformMoneyFormat()));
                    }
                    conn.SaveChanges();
                }
            }

            return messages;
        }
 public static BalanceChange DecorateBalanceChange(BALANCE_CHANGE bc)
 {
     return new BalanceChange
     {
         AccountID = bc.AccountID,
         Amount = bc.Amount,
         ChangeType = (BalanceChangeType)bc.ChangeType,
         CurrencyToDepoRate = 1,
         Description = bc.Description,
         ID = bc.ID,
         ValueDate = bc.ValueDate,
         PositionId = bc.Position
     };
 }
        public AccountRegistrationStatus RegisterAccount(PlatformUser user,
            string accountCurrency, int startBalance, decimal maxLeverage, string completedPassword, bool autoSignIn)
        {
            // проверить заполнение логина-почты-баланса-плеча
            if (user.Login.Length < PlatformUser.LoginLenMin ||
                user.Login.Length > PlatformUser.LoginLenMax) return AccountRegistrationStatus.IncorrectLogin;
            if (user.Email.Length < PlatformUser.EmailLenMin ||
                user.Email.Length > PlatformUser.EmailLenMax) return AccountRegistrationStatus.IncorrectEmail;
            if (!PlatformUser.CheckLoginSpelling(user.Login)) return AccountRegistrationStatus.IncorrectLogin;
            if (startBalance < Account.MinimumStartDepo || startBalance > Account.MaximumStartDepo)
                return AccountRegistrationStatus.IncorrectBalance;
            if (maxLeverage < 0) maxLeverage = 0;
            else if (maxLeverage > Account.MaximumDepoLeverage) maxLeverage = Account.MaximumDepoLeverage;
            long hash;
            if (!TradingContractDictionary.Instance.GetTickers(out hash).Any(c => c.ActiveBase == accountCurrency ||
                c.ActiveCounter == accountCurrency)) return AccountRegistrationStatus.WrongCurrency;

            // сгенерировать пароль
            if (string.IsNullOrEmpty(completedPassword))
            {
                string pwrd;
                while (true)
                {
                    pwrd = RandomWordGenerator.Password(new Random().Next(2) + 2);
                    if (pwrd.Length < PlatformUser.PasswordLenMin || pwrd.Length > PlatformUser.PasswordLenMax)
                        continue;
                    break;
                }
                user.Password = pwrd;
            }
            else
                user.Password = completedPassword;
            user.RegistrationDate = DateTime.Now;
            Logger.InfoFormat("RegisterAccount (email={0}, login={1}, pwrd={2}{3})",
                user.Email, user.Login, user.Password, string.IsNullOrEmpty(completedPassword) ? " (auto)" : "");
            if (string.IsNullOrEmpty(user.Title))
                user.Title = string.IsNullOrEmpty(user.Name) ? user.Login : user.Name;
            user.RoleMask = UserRole.Trader;

            // попытка создать пользователя и открыть счет
            using (var ctx = DatabaseContext.Instance.Make())
            {
                try
                {
                    // проверка дублирования
                    var existUser = ctx.PLATFORM_USER.FirstOrDefault(u => u.Email.Equals(user.Email, StringComparison.OrdinalIgnoreCase));
                    Logger.InfoFormat("Регистрация пользователя: email {0} занят", user.Email);
                    if (existUser != null) return AccountRegistrationStatus.DuplicateEmail;
                    existUser = ctx.PLATFORM_USER.FirstOrDefault(u => u.Login == user.Login);
                    if (existUser != null) return AccountRegistrationStatus.DuplicateLogin;
                }
                catch (Exception ex)
                {
                    Logger.Error("Ошибка в RegisterAccount(checks)", ex);
                    return AccountRegistrationStatus.ServerError;
                }

                // в рамках одной транзакции создать логин и счет
                //using (var transaction = ctx.Connection.BeginTransaction())
                {
                    DbTransaction transaction;
                    try
                    {
                        if (((IObjectContextAdapter)ctx).ObjectContext.Connection.State != ConnectionState.Open)
                            ((IObjectContextAdapter)ctx).ObjectContext.Connection.Open();
                        Logger.Info("Connection's opened");
                        transaction = ((IObjectContextAdapter)ctx).ObjectContext.Connection.BeginTransaction();
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("RegisterAccount - ошибка в ctx.Connection.BeginTransaction", ex);
                        return AccountRegistrationStatus.ServerError;
                    }

                    try
                    {
                        // добавить пользователя
                        var userBase = LinqToEntity.UndecoratePlatformUser(user);
                        ctx.PLATFORM_USER.Add(userBase);

                        // добавить счет
                        var account = new ACCOUNT
                        {
                            AccountGroup = defaultDemoAccountGroupCode,
                            MaxLeverage = maxLeverage,
                            Balance = startBalance,
                            UsedMargin = 0,
                            Currency = accountCurrency,
                            Description = string.Format("demo account for {0}", user.Login),
                            Status = (int)Account.AccountStatus.Created,
                            TimeCreated = DateTime.Now,
                        };
                        try
                        {
                            ctx.ACCOUNT.Add(account);
                            // сохранить изменения (добавление пользователя и счета, нужны ID)
                            ctx.SaveChanges();
                        }
                        catch (Exception ex)
                        {
                            Logger.Error("RegisterAccount - ACCOUNT adding error", ex);
                            return AccountRegistrationStatus.ServerError;
                        }

                        // добавить кошелек
                        try
                        {
                            var wallet = new WALLET
                            {
                                Balance = 0,
                                Currency = accountCurrency,
                                Password = user.Password,
                                User = userBase.ID
                            };
                            ctx.WALLET.Add(wallet);
                        }
                        catch (Exception ex)
                        {
                            Logger.Error("RegisterAccount - WALLET adding error", ex);
                            return AccountRegistrationStatus.ServerError;
                        }

                        // пользователь-счет
                        var userAccount = new PLATFORM_USER_ACCOUNT
                        {
                            PlatformUser = userBase.ID,
                            Account = account.ID,
                            RightsMask = (int)AccountRights.Управление
                        };
                        ctx.PLATFORM_USER_ACCOUNT.Add(userAccount);

                        // перевод на счет
                        var trans = new BALANCE_CHANGE
                        {
                            ValueDate = DateTime.Now,
                            AccountID = account.ID,
                            Amount = startBalance,
                            ChangeType = (int)BalanceChangeType.Deposit,
                            Description = "initial deposit"
                        };
                        ctx.BALANCE_CHANGE.Add(trans);

                        // сделать сигнальщиком
                        if (makeNewlyAddedUsersSignallers)
                            MakeNewlyRegisteredAccountSignaller(ctx, userBase, account);

                        // сохранить все изменения
                        ctx.SaveChanges();
                        if (string.IsNullOrEmpty(completedPassword))
                            if (!SendEmailOnNewAccount(user, true))
                            {
                                transaction.Rollback();
                                return AccountRegistrationStatus.EmailDeliveryError;
                            }

                        transaction.Commit();
                        ((IObjectContextAdapter)ctx).ObjectContext.Connection.Close();
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("Ошибка в RegisterAccount (login={0}, email={1}) : {2}",
                                           user.Login, user.Email, ex);
                        transaction.Rollback();
                        ((IObjectContextAdapter)ctx).ObjectContext.Connection.Close();
                        return AccountRegistrationStatus.ServerError;
                    }
                } // using (transaction ...
            }
            return AccountRegistrationStatus.OK;
        }