public static ACCOUNT UndecorateAccount(Account src) { var dest = new ACCOUNT(); UndecorateAccount(dest, src); return(dest); }
/// <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; }
/// <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 static void DecorateAccount(Account dest, ACCOUNT src) { dest.ID = src.ID; dest.Currency = src.Currency; dest.Group = src.AccountGroup; dest.MaxLeverage = (float)src.MaxLeverage; dest.Balance = src.Balance; dest.TimeCreated = src.TimeCreated; dest.TimeBlocked = src.TimeBlocked; dest.Status = (Account.AccountStatus)src.Status; }
public static void DecorateAccount(Account dest, ACCOUNT src) { dest.ID = src.ID; dest.Currency = src.Currency; dest.Group = src.AccountGroup; dest.MaxLeverage = (float) src.MaxLeverage; dest.Balance = src.Balance; dest.TimeCreated = src.TimeCreated; dest.TimeBlocked = src.TimeBlocked; dest.Status = (Account.AccountStatus) src.Status; }
/// <summary> /// мапинг объекта Account в ACCOUNT, с использованием переданного контекста /// Это нужно для того, что бы потом была возможномть выполнить обновление (потому что обновление должно выполняться в этом же контексте) /// </summary> /// <param name="dest">его значения обновятся</param> /// <param name="src">объек для мапинга</param> /// <returns></returns> public static void UndecorateAccount(ACCOUNT dest, Account src) { dest.Currency = src.Currency; dest.AccountGroup = src.Group; dest.MaxLeverage = (decimal)src.MaxLeverage; dest.UsedMargin = src.UsedMargin; dest.Balance = src.Balance; dest.Status = (int)src.Status; dest.TimeCreated = src.TimeCreated; dest.TimeBlocked = src.TimeBlocked; }
public AccountItem(ACCOUNT account) { ID = account.ID; Currency = account.Currency; Group = account.AccountGroup; MaxLeverage = (float) account.MaxLeverage; Balance = account.Balance; TimeCreated = account.TimeCreated; TimeBlocked = account.TimeBlocked; Status = (AccountStatus) account.Status; }
public static Account DecorateAccount(ACCOUNT ac) { var account = new Account { ID = ac.ID, Currency = ac.Currency, Group = ac.AccountGroup, MaxLeverage = (float)ac.MaxLeverage, Balance = ac.Balance, TimeCreated = ac.TimeCreated, TimeBlocked = ac.TimeBlocked, Status = (Account.AccountStatus)ac.Status }; return account; }
public static Account DecorateAccount(ACCOUNT ac) { var account = new Account { ID = ac.ID, Currency = ac.Currency, Group = ac.AccountGroup, MaxLeverage = (float)ac.MaxLeverage, Balance = ac.Balance, TimeCreated = ac.TimeCreated, TimeBlocked = ac.TimeBlocked, Status = (Account.AccountStatus)ac.Status }; return(account); }
private RobotContextBacktest MakeRobotContext(ACCOUNT accountData, List<BaseRobot> robots) { var timeFrom = testOnly ? accountData.TimeCreated : accountData.TimeCreated.AddMinutes(rand.Next(60*24*9)); try { var context = new RobotContextBacktest((tickers, end) => { }) { TimeFrom = timeFrom }; context.TimeFrom = timeFrom; context.TimeTo = endTime; context.AccountInfo = new Account { Currency = accountData.Currency, Group = accountData.AccountGroup, Balance = accountData.Balance, Equity = accountData.Balance, ID = accountData.ID }; foreach (var robot in robots) { context.SubscribeRobot(robot); robot.Initialize(context, CurrentProtectedContext.Instance); } context.InitiateTest(); return context; } catch (Exception ex) { Logger.Error("Error in MakeRobotContext()", ex); throw; } }
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; }
private void PerformMarginCall(ACCOUNT ac) { // !! предусмотреть нотификацию? }
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; } }
public static decimal CalculateAccountEquityWithShares(TradeSharpConnection ctx, ACCOUNT account, int accountOwnerId, Dictionary<string, QuoteData> quotes, out List<AccountShare> accountShares, out bool noQuoteError) { accountShares = new List<AccountShare>(); var orders = ctx.POSITION.Where(p => p.AccountID == account.ID && p.State == (int)PositionState.Opened).ToList().Select(LinqToEntity.DecorateOrder).ToList(); var curProfit = DalSpot.Instance.CalculateOpenedPositionsCurrentResult(orders, quotes, account.Currency, out noQuoteError); if (noQuoteError) return account.Balance; var equity = (decimal)curProfit + account.Balance; // паи владельцев accountShares = ctx.ACCOUNT_SHARE.Where(s => s.Account == account.ID).ToList().Select(s => { var sh = LinqToEntity.DecorateAccountShare(s); sh.ShareMoney = sh.SharePercent * equity / 100; return sh; }).ToList(); if (accountShares.Count == 0) { // прописать долю владельца accountShares.Add(new AccountShare { ShareMoney = equity, SharePercent = 100, UserId = accountOwnerId }); } return equity; }
private RequestStatus CheckShareAndUpdateSubscriberWallet(List<AccountShare> shares, PLATFORM_USER subscriber, ACCOUNT account, Dictionary<string, QuoteData> quotes, out decimal amountInAccountCurx) { amountInAccountCurx = 0; var subscribersShare = shares.FirstOrDefault(s => s.UserId == subscriber.ID); if (subscribersShare == null && withdrawNotInvest) { Logger.ErrorFormat("CheckShareAndUpdateSubscriberWallet(acc={0}, user={1}) - у пользователя нет вклада", accountId, subscriber.Login); return RequestStatus.BadRequest; } // посчитать сумму вложения в валюте целевого счета var ownerWallet = ctx.WALLET.First(w => w.User == subscriber.ID); string errorStr; var calculatedAmountInAccountCurx = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency(account.Currency, ownerWallet.Currency, (double) sumInWalletCurrency, quotes, out errorStr); if (!calculatedAmountInAccountCurx.HasValue) { Logger.Error("CheckShareAndUpdateSubscriberWallet - невозможно перевести " + account.Currency + " в " + ownerWallet.Currency + ": " + errorStr); return RequestStatus.ServerError; } amountInAccountCurx = calculatedAmountInAccountCurx.Value; // завести денег в ПАММ - списать с кошелька подписчика if (!withdrawNotInvest) { // списать деньги с кошелька подписчика if (ownerWallet.Balance < sumInWalletCurrency) { Logger.ErrorFormat( "CheckShareAndUpdateSubscriberWallet({0} на счет {1}) - сумма инвестирования {2} больше баланса кошелька ({3})", login, accountId, sumInWalletCurrency, ownerWallet.Balance); return RequestStatus.MarginOrLeverageExceeded; } ownerWallet.Balance -= sumInWalletCurrency; } else { // вывести все? if (withdrawAll) { amountInAccountCurx = subscribersShare.ShareMoney; string errorDepoAmountStr; var calculatedAmountInWalletCurx = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency( ownerWallet.Currency, account.Currency, (double) amountInAccountCurx, quotes, out errorDepoAmountStr); if (!calculatedAmountInWalletCurx.HasValue) { Logger.Error("CheckShareAndUpdateSubscriberWallet - (расчет суммы вывода) невозможно перевести " + account.Currency + " в " + ownerWallet.Currency + ": " + errorDepoAmountStr); return RequestStatus.ServerError; } sumInWalletCurrency = calculatedAmountInWalletCurx.Value; } else { // не превышает ли выводимая сумма долю вкладчика? if (calculatedAmountInAccountCurx > subscribersShare.ShareMoney) { Logger.ErrorFormat("CheckShareAndUpdateSubscriberWallet({0} на счет {1}) - сумма вывода {2} больше доли пайщика ({3})", login, accountId, calculatedAmountInAccountCurx, subscribersShare.ShareMoney); return RequestStatus.BadRequest; } subscribersShare.ShareMoney -= calculatedAmountInAccountCurx.Value; // выводится, фактически, вся сумма? if (subscribersShare.ShareMoney < MinInvestAmountOnPamm) { Logger.InfoFormat("CheckShareAndUpdateSubscriberWallet({0} на счет {1}) - сумма вывода {2} примерно равна доле пайщика ({3}), выводится все", login, accountId, calculatedAmountInAccountCurx, subscribersShare.ShareMoney); withdrawAll = true; subscribersShare.ShareMoney = 0; } } ownerWallet.Balance += sumInWalletCurrency; } return RequestStatus.OK; }
private void MakeTestContents() { // добавить тестовый счет var group = conn.ACCOUNT_GROUP.First(g => !g.IsReal); group.SwapFree = false; account = new ACCOUNT { AccountGroup = group.Code, Currency = "USD", Balance = 10000, Description = "test", Status = (int) Account.AccountStatus.Created }; conn.ACCOUNT.Add(account); conn.SaveChanges(); // задать всем дефолтовый своп foreach (var spot in conn.SPOT) { spot.SwapBuy = SwapBuy; spot.SwapSell = SwapSell; } // создать сделки по счету allPositions = PositionMaker.MakePositions(conn, account.ID); conn.SaveChanges(); foreach (var pos in allPositions) { // расчетное значение своп-а var swap = DalSpot.Instance.GetAbsValue(pos.Symbol, pos.Side > 0 ? SwapBuy : SwapSell); swap = swap * pos.Volume; // перевести своп в валюту счета string errorStr; swap = DalSpot.Instance.ConvertToTargetCurrency(pos.Symbol, false, account.Currency, (double)swap, QuoteStorage.Instance.ReceiveAllData(), out errorStr) ?? 0; swapByPos.Add(pos, swap); } }
public static ACCOUNT UndecorateAccount(Account src) { var dest = new ACCOUNT(); UndecorateAccount(dest, src); return dest; }
/// <summary> /// мапинг объекта Account в ACCOUNT, с использованием переданного контекста /// Это нужно для того, что бы потом была возможномть выполнить обновление (потому что обновление должно выполняться в этом же контексте) /// </summary> /// <param name="dest">его значения обновятся</param> /// <param name="src">объек для мапинга</param> /// <returns></returns> public static void UndecorateAccount(ACCOUNT dest, Account src) { dest.Currency = src.Currency; dest.AccountGroup = src.Group; dest.MaxLeverage = (decimal)src.MaxLeverage; dest.UsedMargin = src.UsedMargin; dest.Balance = src.Balance; dest.Status = (int)src.Status; dest.TimeCreated = src.TimeCreated; dest.TimeBlocked = src.TimeBlocked; }
public void Setup() { // подыграть за торговый контракт SetupFakeServer(); // инициализировать словари (прежде всего - словарь тикеров) TradeSharpDictionary.Initialize(MoqTradeSharpDictionary.Mock); connection = TradeSharpConnectionPersistent.InitializeTradeSharpConnection(); // пользователь - владелец тестового сервиса var ownerUser = new PLATFORM_USER { Email = "*****@*****.**", Login = "******", Title = "Vafel", RoleMask = 0, Password = "******", RegistrationDate = DateTime.Now }; connection.PLATFORM_USER.Add(ownerUser); connection.SaveChanges(); // добавить категорию сигналов var srv = new SERVICE { FixedPrice = 0, Currency = "USD", User = ownerUser.ID }; connection.SERVICE.Add(srv); connection.SaveChanges(); serviceId = srv.ID; // добавить пользователя var user = new PLATFORM_USER { Email = "*****@*****.**", Login = "******", Password = "******", Title = "test", RegistrationDate = DateTime.Now }; connection.PLATFORM_USER.Add(user); connection.SaveChanges(); testUserId = user.ID; // добавить счет и сделок var group = connection.ACCOUNT_GROUP.First(g => !g.IsReal); var account = new ACCOUNT { AccountGroup = group.Code, Currency = AccountCurrency, Balance = 30000 }; connection.ACCOUNT.Add(account); connection.SaveChanges(); testAccountId = account.ID; // назначить пользователя владельцем счета connection.PLATFORM_USER_ACCOUNT.Add(new PLATFORM_USER_ACCOUNT { Account = testAccountId, PlatformUser = testUserId, RightsMask = (int) AccountRights.Управление }); // подписать счет на сигнал connection.SUBSCRIPTION.Add(new SUBSCRIPTION { User = testUserId, Service = serviceId, RenewAuto = true, TimeEnd = DateTime.Now.Date.AddDays(1) }); connection.SUBSCRIPTION_SIGNAL.Add(new SUBSCRIPTION_SIGNAL { User = testUserId, Service = serviceId, AutoTrade = true, PercentLeverage = 120, MinVolume = 10000, TargetAccount = testAccountId }); connection.SaveChanges(); // позиции MakeOrdersForTest(); foreach (var order in ordersForTest) { var pos = LinqToEntity.UndecorateOpenedPosition(order); connection.POSITION.Add(pos); } connection.SaveChanges(); // прописать срез котировок var nowTime = DateTime.Now; Contract.Util.BL.QuoteStorage.Instance.UpdateValues(new [] { "EURUSD", "GBPUSD", "USDJPY", "EURGBP" }, new [] { new QuoteData(1.3820f, 1.3822f, nowTime), new QuoteData(1.5350f, 1.5354f, nowTime), new QuoteData(90.81f, 90.83f, nowTime), new QuoteData(1.1107f, 1.1112f, nowTime) } ); }
private void MakeTestData() { paidService = conn.SERVICE.First(s => s.Currency == "USD"); srvOwner = paidService.PLATFORM_USER; srvSubscriber = conn.PLATFORM_USER.First(u => u.WALLET.Currency == "USD" && u.ID != srvOwner.ID); // аккаунт с дольками и открытыми позами accountShared = conn.ACCOUNT.First(a => a.POSITION.Count > 1 && a.POSITION.Count < 200); accountSharedOwner = (from pa in conn.PLATFORM_USER_ACCOUNT join u in conn.PLATFORM_USER on pa.PlatformUser equals u.ID where pa.Account == accountShared.ID select u).First(); // добавить ПАММ-сервис conn.SERVICE.Add(new SERVICE { Currency = "USD", ServiceType = (int) PaidServiceType.PAMM, AccountId = accountShared.ID, User = accountSharedOwner.ID, Comment = "PAMMMmm" }); // добавить дольки var oneMoreUser = conn.PLATFORM_USER.First(u => u.ID != accountSharedOwner.ID); conn.ACCOUNT_SHARE.Add(new ACCOUNT_SHARE { Account = accountShared.ID, Share = 55, ShareOwner = accountSharedOwner.ID }); conn.ACCOUNT_SHARE.Add(new ACCOUNT_SHARE { Account = accountShared.ID, Share = 45, ShareOwner = oneMoreUser.ID }); conn.SaveChanges(); }
public void TestInvestInPAMM() { // PAMM-инвестор var pammInvestor = new PLATFORM_USER { Email = "*****@*****.**", Login = "******", Password = "******", RegistrationDate = DateTime.Now, RoleMask = (int) UserRole.Trader, Title = "trader" }; conn.PLATFORM_USER.Add(pammInvestor); conn.SaveChanges(); var wallet = new WALLET { User = pammInvestor.ID, Balance = 160000, Currency = "USD", Password = "******" }; conn.WALLET.Add(wallet); conn.SaveChanges(); // посчитать, что было ДО инвестирования в ПАММ List<AccountShare> shares; bool noQuoteError; WalletManager.CalculateAccountEquityWithShares(conn, accountShared, accountSharedOwner.ID, Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData(), out shares, out noQuoteError); // инвестировать в ПАММ const decimal amountToInvest = 10000; var oldBalance = accountShared.Balance; var status = walletManager.InvestInPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, amountToInvest); Assert.AreEqual(RequestStatus.OK, status, "InvestInPAMM - должно быть ОК"); accountShared = conn.ACCOUNT.First(a => a.ID == accountShared.ID); var shouldBeBalance = oldBalance + amountToInvest; Assert.IsTrue(shouldBeBalance.RoughCompares(accountShared.Balance, 0.1M), "InvestInPAMM - баланс счета должен увеличиться на сумму вложения"); var newShares = conn.ACCOUNT_SHARE.Where(s => s.Account == accountShared.ID).ToList(); Assert.AreEqual(shares.Count + 1, newShares.Count, "InvestInPAMM - добавился один пай"); var sumSharesPercent = newShares.Sum(s => s.Share); Assert.IsTrue(100M.RoughCompares(sumSharesPercent, 0.000001M), "InvestInPAMM - сумма паев осталась 100%"); Assert.IsTrue(newShares.Any(s => s.ShareOwner == pammInvestor.ID), "InvestInPAMM - новый владелец должен быть в списке пайщиков"); Assert.IsTrue(conn.SUBSCRIPTION.Any(s => s.User == pammInvestor.ID), "InvestInPAMM - должна появиться подписка"); // инвестировать еще денег const decimal moreMoney = 145201.55M; status = walletManager.InvestInPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, moreMoney); Assert.AreEqual(RequestStatus.OK, status, "InvestInPAMM (повторно) - должно быть ОК"); var updatedNewShares = conn.ACCOUNT_SHARE.Where(s => s.Account == accountShared.ID).ToList(); Assert.AreEqual(newShares.Count, updatedNewShares.Count, "InvestInPAMM (повторно) - количество паев не должно меняться"); sumSharesPercent = updatedNewShares.Sum(s => s.Share); Assert.IsTrue(100M.RoughCompares(sumSharesPercent, 0.000001M), "InvestInPAMM (повторно) - сумма паев осталась 100%"); status = walletManager.InvestInPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, moreMoney); Assert.AreEqual(RequestStatus.MarginOrLeverageExceeded, status, "InvestInPAMM (превышение баланса) - должно быть MarginOrLeverageExceeded"); // вывести из ПАММа кусочек const decimal withdrawnMoney = 50.25M; var balanceBeforeWth = conn.WALLET.First(w => w.User == pammInvestor.ID).Balance; status = walletManager.WithdrawFromPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, withdrawnMoney, false); Assert.AreEqual(RequestStatus.OK, status, "InvestInPAMM (вывод средств) - должно быть OK"); var sharesAfterWithdraw = conn.ACCOUNT_SHARE.Where(s => s.Account == accountShared.ID).ToList(); var balanceAfterWth = conn.WALLET.First(w => w.User == pammInvestor.ID).Balance; Assert.IsTrue(balanceBeforeWth.RoughCompares(balanceAfterWth - withdrawnMoney, 0.005M), "баланс должен увеличиться на сумму вывода"); Assert.AreEqual(updatedNewShares.Count, sharesAfterWithdraw.Count, "InvestInPAMM (вывод средств) - количество паёв не должно измениться"); Assert.IsTrue(conn.SUBSCRIPTION.Any(s => s.User == pammInvestor.ID), "InvestInPAMM (вывод средств) - должна остаться подписка"); // попробовать вывести слишком много status = walletManager.WithdrawFromPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, 1000000, false); Assert.AreEqual(RequestStatus.BadRequest, status, "InvestInPAMM (вывод средств) - должно быть BadRequest"); // вывести остаток status = walletManager.WithdrawFromPAMM(ProtectedOperationContext.MakeServerSideContext(), pammInvestor.Login, accountShared.ID, 0, true); Assert.AreEqual(RequestStatus.OK, status, "InvestInPAMM (вывод всех средств) - должно быть OK"); Assert.IsFalse(conn.SUBSCRIPTION.Any(s => s.User == pammInvestor.ID), "InvestInPAMM (вывод всех средств) - должна удалиться подписка"); Assert.IsFalse(conn.ACCOUNT_SHARE.Any(s => s.ShareOwner == pammInvestor.ID), "InvestInPAMM (вывод всех средств) - должна удалиться долька нашего пайщика"); }
private static Wallet PutMoneyOnUserOwnedAccount(int accountId, decimal amountInSrcCurrency, out WalletError error, WALLET wallet, ACCOUNT account, TradeSharpConnection ctx, PLATFORM_USER user) { // достаточно ли денег в кошельке? if (amountInSrcCurrency > wallet.Balance) { error = WalletError.InsufficientFunds; return null; } // перевести объем в валюту счета var amount = amountInSrcCurrency; if (account.Currency != wallet.Currency) { // найти котировку и перевести string errorString; var amountTarget = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency(account.Currency, wallet.Currency, (double) amount, QuoteStorage.Instance.ReceiveAllData(), out errorString); if (!amountTarget.HasValue) { Logger.ErrorFormat("DepositOrWithdraw({0} {1}): {2}", amountInSrcCurrency, account.Currency + "/" + wallet.Currency, errorString); error = WalletError.CurrencyExchangeFailed; return null; } amount = amountTarget.Value; } // списать с кошелька и пополнить счет wallet.Balance -= amountInSrcCurrency; account.Balance += amount; var dateOper = DateTime.Now; var balanceChange = ctx.BALANCE_CHANGE.Add(new BALANCE_CHANGE { AccountID = accountId, Amount = amount, ChangeType = (int) BalanceChangeType.Deposit, ValueDate = dateOper, Description = "Пополнение с кошелька №" + wallet.User }); try { ctx.SaveChanges(); } catch (Exception ex) { Logger.Error("DepositOrWithdraw() - error saving balance change", ex); error = WalletError.ServerError; return null; } var balanceChangeId = balanceChange.ID; ctx.TRANSFER.Add(new TRANSFER { Amount = -amountInSrcCurrency, TargetAmount = -amountInSrcCurrency, User = user.ID, Comment = "Т. счет №" + account.ID, ValueDate = dateOper, BalanceChange = balanceChangeId, }); try { ctx.SaveChanges(); } //catch (System.Data.Entity.Infrastructure.DbUpdateConcurrencyException) //{ //} catch (Exception ex) { Logger.Error("DepositOrWithdraw() - error saving transfer for user " + user.ID + ", balance change Id: " + balanceChangeId + ", user: " + user.ID, ex); error = WalletError.ServerError; return null; } error = WalletError.OK; return LinqToEntity.DecorateWallet(wallet); }
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; } } }
private bool GetAccountEquityAndUsedMargin(ACCOUNT account, out decimal equity, out decimal usedMargin) { try { decimal exposure; profitCalculator.CalculateAccountExposure(account.ID, out equity, out usedMargin, out exposure, QuoteStorage.Instance.ReceiveAllData(), ManagerAccount.Instance, accountRepository.GetAccountGroup); return true; } catch (Exception ex) { equity = 0; usedMargin = 0; Logger.ErrorFormat("GetAccountEquityAndUsedMargin({0}) error: {1}", account.ID, ex); return false; } }
private void btnCreate_Click(object sender, EventArgs e) { var users = MakeUsersWithNames(); if (users.Count == 0) { MessageBox.Show("Пользователи не созданы (нет записей)"); return; } accountIds.Clear(); var depoPercentiles = tbStartDepo.Text.ToIntArrayUniform(); // каждого занести в БД // для каждого завести кошелек, положить немного денег // завести каждому счет // опционально - завести каждому сигнальный сервис var group = (string) cbGroup.SelectedItem; const int moneyOnWallet = 1250; var currency = tbCurrency.Text; var signalPrice = tbSignalCost.Text.ToDecimalUniformSafe() ?? 1; var timeParts = tbNewAccountOpenTime.Text.Split(new[] {'-'}, StringSplitOptions.RemoveEmptyEntries); var timeStartMin = timeParts[0].Trim(' ').ToDateTimeUniform(); var timeStartMax = timeParts[1].Trim(' ').ToDateTimeUniform(); var minutesBackMax = (int)(timeStartMax - timeStartMin).TotalMinutes; using (var ctx = DatabaseContext.Instance.Make()) foreach (var user in users) { // сам пользователь var usrUnd = LinqToEntity.UndecoratePlatformUser(user); ctx.PLATFORM_USER.Add(usrUnd); ctx.SaveChanges(); var userId = usrUnd.ID; var modelTime = timeStartMax.AddMinutes(-rand.Next(minutesBackMax)); // кошелек var wallet = new WALLET { Balance = moneyOnWallet, Currency = currency, Password = user.Password, User = userId }; ctx.WALLET.Add(wallet); // счет var money = GetRandomDepositSize(depoPercentiles); var roughMoneyPercent = 0.0; if (rand.Next(100) < 20) roughMoneyPercent = rand.NextDouble() - 0.5; else if (rand.Next(100) < 30) roughMoneyPercent = rand.NextDouble() * 100 - 50; money += (int)(money * roughMoneyPercent / 100); var account = new ACCOUNT { AccountGroup = group, Balance = money, Currency = currency, Status = (int) Account.AccountStatus.Created, TimeCreated = modelTime, ReadonlyPassword = user.Password }; ctx.ACCOUNT.Add(account); ctx.SaveChanges(); accountIds.Add(account.ID); // денежный перевод на счет - начальный баланс ctx.BALANCE_CHANGE.Add(new BALANCE_CHANGE { AccountID = account.ID, Amount = money, ChangeType = (int) BalanceChangeType.Deposit, Description = "Initial deposit", ValueDate = account.TimeCreated }); // пользователь-счет ctx.PLATFORM_USER_ACCOUNT.Add(new PLATFORM_USER_ACCOUNT { Account = account.ID, PlatformUser = userId, RightsMask = (int) AccountRights.Управление }); // сервис торг. сигналов if (cbSignallers.Checked) { ctx.SERVICE.Add(new SERVICE { AccountId = account.ID, Currency = currency, FixedPrice = signalPrice, User = userId, ServiceType = (int) PaidServiceType.Signals, Comment = "Сигналы " + user.Login }); } ctx.SaveChanges(); } }
private Wallet GetMoneyFromUserOwnedAccount(int accountId, decimal amountInSrcCurrency, out WalletError error, ACCOUNT account, WALLET wallet, TradeSharpConnection ctx, PLATFORM_USER user) { var amountWallet = amountInSrcCurrency; if (account.Currency != wallet.Currency) { // найти котировку и перевести string errorString; var amountTarget = DalSpot.Instance.ConvertSourceCurrencyToTargetCurrency(wallet.Currency, account.Currency, (double) amountWallet, QuoteStorage.Instance.ReceiveAllData(), out errorString); if (!amountTarget.HasValue) { Logger.ErrorFormat("DepositOrWithdraw({0} {1}): {2} (withdraw)", amountInSrcCurrency, account.Currency + "/" + wallet.Currency, errorString); error = WalletError.CurrencyExchangeFailed; return null; } amountWallet = amountTarget.Value; } // достаточно ли средств на счете? // проверить средства / зарезервированное марж. обеспечение decimal equity, usedMargin; if (!GetAccountEquityAndUsedMargin(account, out equity, out usedMargin)) { error = WalletError.ServerError; return null; } if (equity - usedMargin < amountInSrcCurrency) { error = WalletError.ServerError; return null; } // списать со счета в пользу кошелька wallet.Balance += amountInSrcCurrency; account.Balance -= amountInSrcCurrency; var date = DateTime.Now; var bc = ctx.BALANCE_CHANGE.Add(new BALANCE_CHANGE { AccountID = accountId, Amount = amountInSrcCurrency, ChangeType = (int) BalanceChangeType.Withdrawal, ValueDate = date, Description = "Списание на кошелек №" + wallet.User }); ctx.SaveChanges(); ctx.TRANSFER.Add(new TRANSFER { Amount = amountWallet, TargetAmount = amountWallet, User = user.ID, Comment = "Вывод средств со счета №" + account.ID, ValueDate = date, BalanceChange = bc.ID, }); ctx.SaveChanges(); error = WalletError.OK; return LinqToEntity.DecorateWallet(wallet); }
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); } }
public void MakeNewlyRegisteredAccountSignaller(TradeSharpConnection ctx, PLATFORM_USER user, ACCOUNT account) { try { ctx.SERVICE.Add(new SERVICE { AccountId = account.ID, ServiceType = (int) PaidServiceType.PAMM, Currency = account.Currency, FixedPrice = 1, Comment = "Сигналы " + LinqToEntity.DecoratePlatformUser(user).NameWithInitials, User = user.ID }); } catch (Exception ex) { Logger.ErrorFormat("Ошибка в MakeNewlyRegisteredAccountSignaller(login={0}, account={1}): {2}", user.Login, account.ID, ex); } }