public bool CloseOrder(MarketOrder order, decimal price, PositionExitReason exitReason) { using (var ctx = DatabaseContext.Instance.Make()) { var account = ctx.ACCOUNT.FirstOrDefault(ac => ac.ID == order.AccountID); if (account == null) { Logger.ErrorFormat("Закрытие ордера #{0}: невозможно прочитать данные счета ({1})", order.ID, order.AccountID); return(false); } // провести ордер через биллинг ORDER_BILL bill = null; if (order.State == PositionState.Opened) { bill = BillingManager.ProcessPriceForOrderClosing(order, LinqToEntity.DecorateAccount(account), ctx); } // посчитать результат // и обновить объект order.State = PositionState.Closed; order.PriceExit = (float?)price; var deltaAbs = order.Side * (order.PriceExit.Value - order.PriceEnter); order.ResultPoints = DalSpot.Instance.GetPointsValue(order.Symbol, deltaAbs); var deltaDepo = deltaAbs * order.Volume; var quotes = QuoteStorage.Instance.ReceiveAllData(); string errorStr; var resultedDepo = DalSpot.Instance.ConvertToTargetCurrency(order.Symbol, false, account.Currency, deltaDepo, quotes, out errorStr, false); if (!resultedDepo.HasValue) { Logger.ErrorFormat("#{0} ({1} {2}{3}, {4:f1} пп): ошибка расчета прибыли в валюте депозита - {5}", order.ID, order.Side > 0 ? "B" : "S", order.Symbol, order.Volume, order.ResultPoints, errorStr); return(false); } order.ResultDepo = (float)resultedDepo.Value; //order.Swap = (float)swap; order.ExitReason = exitReason; order.TimeExit = DateTime.Now; var posClosed = LinqToEntity.UndecorateClosedPosition(order); POSITION pos = null; try { // занести ордер в список закрытых позиций (создать новую запись "истории") ctx.POSITION_CLOSED.Add(posClosed); // удалить открытый ордер pos = ctx.POSITION.FirstOrDefault(p => p.ID == order.ID); if (pos == null) { Logger.ErrorFormat("CloseOrder - позиция {0} не найдена", order.ID); ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(null, RequestStatus.ServerError, "crudsav"); return(false); } ctx.POSITION.Remove(pos); // посчитать профиты if (bill != null) { BillingManager.ProcessOrderClosing(order, account, bill, ctx, quotes, brokerRepository.BrokerCurrency); } // сохранить изменения ctx.SaveChanges(); // обновить баланс var resultAbs = Math.Abs(order.ResultDepo); if (!UpdateAccountBalance(ctx, account, (decimal)resultAbs, order.ResultDepo >= 0 ? BalanceChangeType.Profit : BalanceChangeType.Loss, string.Format("результат сделки #{0}", posClosed.ID), DateTime.Now, order.ID)) { Logger.ErrorFormat("Не удалось применить обновление баланса #{0}", posClosed.ID); } } catch (OptimisticConcurrencyException ex) { Logger.Error("CloseOrder - OptimisticConcurrencyException", ex); ctx.Entry(posClosed).State = EntityState.Modified; ((IObjectContextAdapter)ctx).ObjectContext.Refresh(RefreshMode.ClientWins, posClosed); if (pos != null) { ctx.Entry(pos).State = EntityState.Modified; ((IObjectContextAdapter)ctx).ObjectContext.Refresh(RefreshMode.ClientWins, pos); } ctx.SaveChanges(); } catch (Exception ex) { Logger.ErrorFormat("Ошибка закрытия позиции {0} (счет #{1}) (фиксация в БД): {2}", order.ID, order.AccountID, ex); ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(null, RequestStatus.ServerError, "crudsave"); return(false); } } // уведомить клиента ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(order, RequestStatus.OK, ""); // разослать торговый сигнал MakeOrderClosedSignal(order.AccountID, order.ID, (float)price); return(true); }
public RequestStatus GetUserOwnAndSharedAccounts(string login, ProtectedOperationContext secCtx, out List <AccountShared> accounts) { accounts = new List <AccountShared>(); if (!UserSessionStorage.Instance.PermitUserOperation(secCtx, false, true)) { return(RequestStatus.Unauthorized); } try { Wallet userWallet; using (var ctx = DatabaseContext.Instance.Make()) { // получить собственные реальные! счета пользователя var ownAccounts = (from ac in ctx.ACCOUNT join gr in ctx.ACCOUNT_GROUP on ac.AccountGroup equals gr.Code join pa in ctx.PLATFORM_USER_ACCOUNT on ac.ID equals pa.Account join u in ctx.PLATFORM_USER on pa.PlatformUser equals u.ID where u.Login == login && gr.IsReal select ac).ToList() .Select(a => new AccountShared(LinqToEntity.DecorateAccount(a), true) { SharePercent = 100 }) .ToList(); // получить те счета, в которых у запросившего есть доля var shares = (from sh in ctx.ACCOUNT_SHARE join u in ctx.PLATFORM_USER on sh.ShareOwner equals u.ID join ac in ctx.ACCOUNT on sh.Account equals ac.ID join gr in ctx.ACCOUNT_GROUP on ac.AccountGroup equals gr.Code where u.Login == login && gr.IsReal select new AccountShared { Account = new Account { ID = ac.ID, Group = ac.AccountGroup, Currency = ac.Currency, Balance = ac.Balance }, SharePercent = sh.Share }).ToList(); // склеить оба списка ownAccounts.ForEach(a => { var sharedAccount = shares.FirstOrDefault(s => s.Account.ID == a.Account.ID); if (sharedAccount != null) { a.SharePercent = sharedAccount.SharePercent; } }); accounts = ownAccounts.Union(shares, AccountShared.ComparerOnId.Instance).ToList(); if (accounts.Count == 0) { return(RequestStatus.OK); } userWallet = LinqToEntity.DecorateWallet((from w in ctx.WALLET join u in ctx.PLATFORM_USER on w.User equals u.ID where u.Login == login select w).First()); } // посчитать профит (equity) для счетов foreach (var account in accounts) { var equity = profitCalculator.CalculateAccountEquity(account.Account.ID, account.Account.Balance, account.Account.Currency, TradeSharp.Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData(), this); account.Account.Equity = equity; account.ShareMoney = account.Account.Equity * account.SharePercent / 100M; account.ShareMoneyWallet = account.ShareMoney; // посчитать долю в валюте кошелька if (account.Currency == userWallet.Currency) { continue; } string errorString; var shareWallet = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency(userWallet.Currency, account.Currency, (double)account.ShareMoney, TradeSharp.Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData(), out errorString); account.ShareMoneyWallet = shareWallet ?? account.ShareMoney; if (errorString != null) { Logger.ErrorFormat("GetUserOwnAndSharedAccounts({0}) - перевод средств из {1} в {2}: {3}", login, account.Currency, userWallet.Currency, errorString); } } } catch (Exception ex) { Logger.Error("Ошибка в GetUserOwnAndSharedAccounts", ex); return(RequestStatus.ServerError); } return(RequestStatus.OK); }
/// <summary> /// вернуть акаунты, которыми трейдер владеет! /// опционально - исключив демки /// по каждому акаунту посчитать средства и резерв. маржу /// </summary> public AuthenticationResponse GetUserOwnedAccountsWithActualBalance(string login, ProtectedOperationContext secCtx, bool realOnly, out List <Account> accounts) { accounts = new List <Account>(); try { if (UserOperationRightsStorage.IsProtectedOperation(UserOperation.GetAccountDetail)) { if (!UserSessionStorage.Instance.PermitUserOperation(secCtx, UserOperationRightsStorage.IsTradeOperation(UserOperation.GetAccountDetail), false)) { return(AuthenticationResponse.WrongPassword); } } } catch (Exception ex) { Logger.Error("GetUserOwnedAccountsWithActualBalance - PermitUserOperation error", ex); return(AuthenticationResponse.ServerError); } try { using (var ctx = DatabaseContext.Instance.Make()) { try { var user = ctx.PLATFORM_USER.FirstOrDefault(ac => ac.Login == login); if (user == null) { return(AuthenticationResponse.InvalidAccount); } var accountRoles = (from ar in ctx.PLATFORM_USER_ACCOUNT where ar.PlatformUser == user.ID && ar.RightsMask == (int)AccountRights.Управление select ar); foreach (var acRole in accountRoles) { var acId = acRole.Account; var acc = realOnly ? ctx.ACCOUNT.FirstOrDefault(a => a.ID == acId && a.ACCOUNT_GROUP.IsReal) : ctx.ACCOUNT.FirstOrDefault(a => a.ID == acId); if (acc == null) { continue; } // заполнить данные о актуальном балансе и т.д. и т.п. decimal equity, reservedMargin, exposure; profitCalculator.CalculateAccountExposure(acId, out equity, out reservedMargin, out exposure, TradeSharp.Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData(), ManagerAccount.Instance, accountRepository.GetAccountGroup); var accountDec = LinqToEntity.DecorateAccount(acc); accountDec.Equity = equity; accountDec.UsedMargin = reservedMargin; accounts.Add(accountDec); } } catch (Exception ex) { Logger.Error("Ошибка в GetUserOwnedAccountsWithActualBalance", ex); return(AuthenticationResponse.ServerError); } return(AuthenticationResponse.OK); } } catch (Exception ex) { Logger.Error("GetUserOwnedAccountsWithActualBalance - error making DB context", ex); return(AuthenticationResponse.ServerError); } }
/// <summary> /// вызывается дилером - в БД заносится новая поза (открытая либо в процессе открытия) /// отправить уведомление клиенту /// </summary> /// <param name="order">поза</param> /// <param name="posID">ID сущности из БД</param> /// <returns>OK?</returns> public bool SaveOrderAndNotifyClient(MarketOrder order, out int posID) { posID = -1; using (var ctx = DatabaseContext.Instance.Make()) { var account = ctx.ACCOUNT.FirstOrDefault(ac => ac.ID == order.AccountID); if (account == null) { return(false); } // провести ордер через биллинг OrderBill bill = null; if (order.State == PositionState.Opened) { bill = BillingManager.ProcessOrderOpening(order, LinqToEntity.DecorateAccount(account)); } var pos = new POSITION { AccountID = order.AccountID, Comment = order.Comment, ExpertComment = order.ExpertComment, Magic = order.Magic, PendingOrderID = order.PendingOrderID, PriceBest = (decimal?)order.PriceBest, PriceWorst = (decimal?)order.PriceWorst, PriceEnter = (decimal)order.PriceEnter, Side = order.Side, State = ((int)order.State), Stoploss = (decimal?)order.StopLoss, Symbol = order.Symbol, Takeprofit = (decimal?)order.TakeProfit, TimeEnter = order.TimeEnter, TrailLevel1 = (decimal?)order.TrailLevel1, TrailLevel2 = (decimal?)order.TrailLevel2, TrailLevel3 = (decimal?)order.TrailLevel3, TrailLevel4 = (decimal?)order.TrailLevel4, TrailTarget1 = (decimal?)order.TrailTarget1, TrailTarget2 = (decimal?)order.TrailTarget2, TrailTarget3 = (decimal?)order.TrailTarget3, TrailTarget4 = (decimal?)order.TrailTarget4, Volume = order.Volume, MasterOrder = order.MasterOrder }; account.POSITION.Add(pos); try { ctx.SaveChanges(); posID = pos.ID; order.ID = posID; if (bill != null) { BillingManager.SaveNewOrderBill(bill, pos.ID, ctx); } ctx.SaveChanges(); } catch (Exception ex) { Logger.Error("Ошибка сохранения сущности POSITION", ex); ServiceManagerClientManagerProxy.Instance.NewOrderResponse(null, RequestStatus.ServerError, "crudsav"); return(false); } } // отправить уведомление клиенту ServiceManagerClientManagerProxy.Instance.NewOrderResponse(order, RequestStatus.OK, ""); // разослать торговый сигнал? if (order.State == PositionState.Opened) { MakeSignalNewDeal(order.AccountID, order.Symbol, order.Side, order.Volume, order.StopLoss.HasValue ? (decimal)order.StopLoss.Value : (decimal?)null, order.TakeProfit.HasValue ? (decimal)order.TakeProfit.Value : (decimal?)null, posID, order.PriceEnter); } return(true); }