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; }