public static string TradeSignalSetsAreCorrect(AutoTradeSettings sets, SUBSCRIPTION_SIGNAL setsStored)
 {
     var errors = new List<string>();
     if ((int?)sets.VolumeRound != setsStored.VolumeRound) errors.Add("VolumeRound");
     if (sets.HedgingOrdersEnabled != setsStored.HedgingOrdersEnabled) errors.Add("HedgingOrdersEnabled");
     if (sets.PercentLeverage != setsStored.PercentLeverage) errors.Add("PercentLeverage");
     if (sets.MinVolume != setsStored.MinVolume) errors.Add("MinVolume");
     if (sets.StepVolume != setsStored.StepVolume) errors.Add("StepVolume");
     if (sets.MaxLeverage != setsStored.MaxLeverage) errors.Add("MaxLeverage");
     if (sets.MaxVolume != setsStored.MaxVolume) errors.Add("MaxVolume");
     if (sets.TargetAccount != setsStored.TargetAccount) errors.Add("TargetAccount");
     if (sets.TradeAuto != setsStored.AutoTrade) errors.Add("TradeAuto");
     if (sets.FixedVolume != setsStored.FixedVolume) errors.Add("FixedVolume");
     return string.Join(", ", errors);
 }
 public static AutoTradeSettings DecorateAutoTradeSettings(SUBSCRIPTION_SIGNAL cat)
 {
     return(new AutoTradeSettings
     {
         FixedVolume = cat.FixedVolume,
         HedgingOrdersEnabled = cat.HedgingOrdersEnabled,
         MaxLeverage = cat.MaxLeverage,
         MaxVolume = cat.MaxVolume,
         MinVolume = cat.MinVolume,
         PercentLeverage = cat.PercentLeverage ?? 100,
         StepVolume = cat.StepVolume,
         TradeAuto = cat.AutoTrade ?? false,
         VolumeRound = (VolumeRoundType?)cat.VolumeRound,
         TargetAccount = cat.TargetAccount
     });
 }
        public void TestCalcVolume()
        {
            var action = new TradeSignalActionTrade
                {
                    Leverage = 1,
                    OrderId = 9999999,
                    Price = 1.3820f,
                    Side = -1,
                    ServiceId = serviceId,
                    Ticker = "EURUSD"
                };
            var tradeSets = new SUBSCRIPTION_SIGNAL
                {
                    TargetAccount = testAccountId,
                    AutoTrade = true,
                    MaxLeverage = 10,
                    MaxVolume = 100000,
                    PercentLeverage = 120,
                    HedgingOrdersEnabled = true,
                    User = 0
                };

            // расчет объема обычного ордера
            var volume = Dealer.GetNewOrderVolume(action, connection, tradeSets);
            Assert.Greater(volume, 0, "TradeSignalDealer - объем больше 0");

            // превышение плеча
            action.Leverage = 4.1M;
            tradeSets.MaxLeverage = 5;
            volume = Dealer.GetNewOrderVolume(action, connection, tradeSets);
            Assert.AreEqual(volume, 0, "TradeSignalDealer - объем 0 (превышение плеча)");

            // просто сделка по йене
            action.Ticker = "USDJPY";
            action.Price = 92.1f;
            action.Leverage = 2;
            tradeSets.MaxLeverage = 7.6f;
            volume = Dealer.GetNewOrderVolume(action, connection, tradeSets);
            Assert.AreEqual(70000, volume, "TradeSignalDealer - объем USDJPY больше 0");
        }
Exemple #4
0
        public static int GetNewOrderVolume(TradeSignalActionTrade action,
            TradeSharpConnection ctx, SUBSCRIPTION_SIGNAL tradeSets)
        {
            // получить ордера по счету, посчитать актуальный баланс (средства) счета
            try
            {
                var account = ctx.ACCOUNT.FirstOrDefault(a => a.ID == tradeSets.TargetAccount.Value);
                if (account == null)
                {
                    Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: счет не найден",
                        tradeSets.TargetAccount, action.OrderId);
                    return 0;
                }

                var equity = (double)account.Balance;

                // ордера
                var orders = ctx.POSITION.Where(p => p.AccountID == tradeSets.TargetAccount &&
                    p.State == (int)PositionState.Opened).ToList().Select(o => LinqToEntity.DecorateOrder(o)).ToList();

                // проверить - нет ли противоположного ордера?
                var quotes = Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData();

                if (orders.Count > 0)
                {
                    if (!(tradeSets.HedgingOrdersEnabled ?? false))
                    {
                        var hasOrdersCounter = orders.Any(p => p.Symbol == action.Ticker && p.Side != action.Side);
                        if (hasOrdersCounter)
                        {
                            logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info, LogMsgContraOrders,
                                1000 * 60 * 90, "Ордер {0} {1}, счет {2} - есть встречные ордера",
                                action.Side > 0 ? "BUY" : "SELL", action.Ticker, tradeSets.TargetAccount);
                            return 0;
                        }
                    }

                    // посчитать профит по позам
                    bool noQuoteError;
                    var openResult = DalSpot.Instance.CalculateOpenedPositionsCurrentResult(
                        orders, quotes, account.Currency, out noQuoteError);
                    if (noQuoteError)
                    {
                        logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmCalcNoQuote,
                            1000 * 60 * 90, "GetNewOrderVolume - нет котировки");
                        return 0;
                    }
                    equity += openResult;
                }

                if (equity <= 0)
                {
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgEquityIsNil,
                            1000 * 60 * 90, "Баланс счета {0}: {1}", account.ID, equity);
                    return 0;
                }

                // посчитать объем
                var volumeDepo = (tradeSets.PercentLeverage ?? 100) / 100f * equity * (double)action.Leverage;
                // пересчитать объем в базовую валюту
                string errorStr;
                var volumeBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency, volumeDepo,
                                                         quotes, out errorStr);
                if (!volumeBase.HasValue)
                {
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmToBase,
                            1000 * 60 * 90, "GetNewOrderVolume - невозможно посчитать объем по сделке {0}, валюта счета {1}: {2}",
                            action.Ticker, account.Currency, errorStr);
                    return 0;
                }

                // округлить объем
                var volume = MarketOrder.RoundDealVolume((int)volumeBase,
                    (VolumeRoundType)(tradeSets.VolumeRound ?? (int)VolumeRoundType.Ближайшее),
                    tradeSets.MinVolume ?? 10000, tradeSets.StepVolume ?? 10000);
                if (volume == 0)
                {
                    var msg = string.Format("Полученный объем входа ({0}) округлен до 0", (int)volumeBase);
                    logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error,
                        LogMsgVolmRoundToZero, 1000 * 60 * 90, msg);
                    return 0;
                }

                // проверить на превышение плеча
                if ((tradeSets.MaxLeverage ?? 0) > 0)
                {
                    var totalExposure = 0M;
                    var ordersBySignaller = orders.Where(position =>
                    {
                        int orderSignalCatId, parentDealId;
                        if (MarketOrder.GetTradeSignalFromDeal(position, out orderSignalCatId, out parentDealId))
                            return orderSignalCatId == action.ServiceId;
                        return false;
                    }).GroupBy(o => o.Symbol).ToDictionary(o => o.Key, o => o.ToList());

                    foreach (var orderByTicker in ordersBySignaller)
                    {
                        // суммарная экспозиция
                        var exp = orderByTicker.Value.Sum(o => o.Side * o.Volume);
                        if (orderByTicker.Key == action.Ticker)
                            exp += action.Side * volume;
                        if (exp == 0) continue;

                        // перевести экспозицию в валюту депозита
                        var expBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency,
                                                                               volumeDepo,
                                                                               quotes, out errorStr);
                        if (!expBase.HasValue)
                        {
                            logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgExposureNoQuote,
                                                                  1000 * 60 * 90,
                                                                  "GetNewOrderVolume - невозможно посчитать экспозицию по сделке " +
                                                                  "{0}, тикер {1}: {2}",
                                                                  action.Ticker, orderByTicker.Key, errorStr);
                            return 0;
                        }

                        totalExposure += Math.Abs(expBase.Value);
                    }
                    var totalLeverage = (double)totalExposure / equity;
                    // ReSharper disable PossibleInvalidOperationException
                    if (totalLeverage > tradeSets.MaxLeverage.Value)
                    // ReSharper restore PossibleInvalidOperationException
                    {
                        logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgMaxLevExceeded,
                                                                  1000 * 60 * 90,
                                                                  "GetNewOrderVolume - макс плечо ({0}) превышено, " +
                                                                  "тикер {1}: плечо составит {2}",
                                                                  tradeSets.MaxLeverage.Value,
                                                                  action.Ticker, totalLeverage);
                        return 0;
                    }
                }

                return volume;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: {2}",
                    tradeSets.TargetAccount, action.OrderId, ex);
            }

            return 0;
        }
        public bool SubscribeOnService(TradeSharpConnection ctx,
            int userId, int serviceId, bool renewAuto, bool unsubscribe,
            AutoTradeSettings tradeSets, out WalletError error)
        {
            // имеющаяся подписка
            var subs = ctx.SUBSCRIPTION.FirstOrDefault(s => s.Service == serviceId && s.User == userId);

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

                return true;
            }

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

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

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

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

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

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

            error = WalletError.OK;
            return true;
        }
        public void TestSubscribeOnCustomPortfolio()
        {
            var managerTrade = ManagerTrade.Instance;
            var portfolio = new TopPortfolio
                {
                    Criteria = "P",
                    DescendingOrder = true,
                    ParticipantCount = 6,
                    Name = "UserGeniusExclusiveTop",
                };
            var tradeSets = AutoTradeSettingsSampler.MakeSampleTradeSettings();
            tradeSets.TargetAccount = conn.PLATFORM_USER_ACCOUNT.First(pa => pa.PlatformUser == subscriber.ID).Account;
            var status = managerTrade.SubscribeOnPortfolio(ProtectedOperationContext.MakeServerSideContext(),
                                              subscriber.Login, portfolio, null, tradeSets);

            Assert.AreEqual(RequestStatus.OK, status, "SubscribeOnPortfolio - удалось подписаться");
            // проверить количество подписок
            var userSubsCount = conn.SUBSCRIPTION.Count(s => s.User == subscriber.ID);
            Assert.AreEqual(portfolio.ParticipantCount, userSubsCount, "SubscribeOnPortfolio - подписался на всех в портфеле");

            // проверить настройки авто-торговли
            var subSettings = conn.SUBSCRIPTION_SIGNAL.First(ss => ss.User == subscriber.ID);
            var wrongFields = AutoTradeSettingsSampler.TradeSignalSetsAreCorrect(tradeSets, subSettings);
            if (!string.IsNullOrEmpty(wrongFields))
                Assert.Fail("SubscribeOnPortfolio - настройки авто-торговли не сохранены в подписке: " + wrongFields);

            // настройки авто-торговли для самого портфеля
            var portfolioTradeSets = (from upf in conn.USER_TOP_PORTFOLIO
                                      join pf in conn.TOP_PORTFOLIO on upf.Portfolio equals pf.Id
                                      where upf.User == subscriber.ID
                                      select upf).FirstOrDefault();
            Assert.IsNotNull(portfolioTradeSets, "SubscribeOnPortfolio - портфель создан");
            var portfolioSignalSets = new SUBSCRIPTION_SIGNAL
                                          {
                                              AutoTrade = portfolioTradeSets.AutoTrade,
                                              MaxLeverage = portfolioTradeSets.MaxLeverage,
                                              PercentLeverage = portfolioTradeSets.PercentLeverage,
                                              HedgingOrdersEnabled = portfolioTradeSets.HedgingOrdersEnabled,
                                              FixedVolume = portfolioTradeSets.FixedVolume,
                                              MinVolume = portfolioTradeSets.MinVolume,
                                              MaxVolume = portfolioTradeSets.MaxVolume,
                                              VolumeRound = portfolioTradeSets.VolumeRound,
                                              StepVolume = portfolioTradeSets.StepVolume,
                                              TargetAccount = portfolioTradeSets.TargetAccount
                                          };
            wrongFields = AutoTradeSettingsSampler.TradeSignalSetsAreCorrect(tradeSets, portfolioSignalSets);
            if (!string.IsNullOrEmpty(wrongFields))
                Assert.Fail("SubscribeOnPortfolio - настройки авто-торговли не сохранены в портфеле: " + wrongFields);

            // отписаться от портфеля
            status = managerTrade.UnsubscribePortfolio(ProtectedOperationContext.MakeServerSideContext(),
                                                       subscriber.Login, true, true);
            Assert.AreEqual(RequestStatus.OK, status, "SubscribeOnPortfolio - удалось отписаться");
            userSubsCount = conn.SUBSCRIPTION.Count(s => s.User == subscriber.ID);
            Assert.AreEqual(0, userSubsCount, "SubscribeOnPortfolio - отписался ото всех в портфеле");
        }
 public static AutoTradeSettings DecorateAutoTradeSettings(SUBSCRIPTION_SIGNAL cat)
 {
     return new AutoTradeSettings
     {
         FixedVolume = cat.FixedVolume,
         HedgingOrdersEnabled = cat.HedgingOrdersEnabled,
         MaxLeverage = cat.MaxLeverage,
         MaxVolume = cat.MaxVolume,
         MinVolume = cat.MinVolume,
         PercentLeverage = cat.PercentLeverage ?? 100,
         StepVolume = cat.StepVolume,
         TradeAuto = cat.AutoTrade ?? false,
         VolumeRound = (VolumeRoundType?)cat.VolumeRound,
         TargetAccount = cat.TargetAccount
     };
 }