コード例 #1
0
        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));
        }
コード例 #2
0
        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");
        }
コード例 #3
0
ファイル: Dealer.cs プロジェクト: zhangjiayin/TradeSharp
        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);
        }
コード例 #4
0
        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 - отписался ото всех в портфеле");
        }
コード例 #5
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);
        }