Ejemplo n.º 1
0
        private void MakeSignalNewDeal(
            int accountId,
            string ticker,
            int side,
            int volume,
            decimal?stopLoss,
            decimal?takeProfit,
            int orderId,
            float priceEnter)
        {
            // разослать сигнал подписчикам?
            var signalCat = ManagementTraderList.Instance.IsSignaller(accountId);

            if (!signalCat.HasValue)
            {
                return;
            }
            Logger.InfoFormat("MakeSignalNewDeal (cat={0})", signalCat);

            // посчитать плечо сделки
            var leverage = CalculateDealLeverage(accountId, ticker, volume);

            if (leverage == null)
            {
                Logger.InfoFormat("MakeSignalNewDeal({0}, {1}, {2}, {3}) - leverage is null",
                                  accountId, ticker, side, volume);
                return;
            }

            // таки разослать
            var action = new TradeSignalActionTrade
            {
                ServiceId  = signalCat.Value,
                Price      = priceEnter,
                Side       = side,
                Ticker     = ticker,
                StopLoss   = stopLoss ?? 0,
                TakeProfit = takeProfit ?? 0,
                OrderId    = orderId,
                Leverage   = leverage.Value
            };

            Logger.InfoFormat("MakeSignalNewDeal({0}, {1}, {2}, {3}) - sending signal (leverage is {4:f2})",
                              accountId, ticker, side, volume, leverage.Value);
            ServiceManagerClientManagerProxy.Instance.ProcessTradeSignalAction(action);
        }
Ejemplo n.º 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");
        }
Ejemplo n.º 3
0
 /// <summary>
 /// торгануть по сигналу
 /// </summary>
 private void ProcessTradeSignalActionTrade(TradeSignalActionTrade trade)
 {
 }
Ejemplo n.º 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);
        }
Ejemplo n.º 5
0
        private static void ProcessSignalOpenOrder(TradeSignalActionTrade action)
        {
            try
            {
                var signalRecord = EnqueueProcessedSignalRecord(action);

                using (var ctx = DatabaseContext.Instance.Make())
                {
                    // получить информацию по настройкам торговых сигналов
                    var subscriptions = (from subsSig in ctx.SUBSCRIPTION_SIGNAL
                                         where (subsSig.AutoTrade ?? false) && subsSig.Service == action.ServiceId && subsSig.TargetAccount.HasValue
                                         select subsSig).ToList();

                    foreach (var sub in subscriptions)
                    {
                        var volm = sub.FixedVolume ?? 0;
                        if (volm == 0)
                        {
                            volm = GetNewOrderVolume(action, ctx, sub);
                        }

                        // объем входа недопустимо мал либо ошибка в расчете
                        if (volm == 0)
                        {
                            return;
                        }

                        var order = new MarketOrder
                        {
                            // ReSharper disable PossibleInvalidOperationException
                            AccountID = sub.TargetAccount.Value,
                            // ReSharper restore PossibleInvalidOperationException
                            Volume        = volm,
                            Side          = action.Side,
                            Symbol        = action.Ticker,
                            StopLoss      = (float?)action.StopLoss,
                            TakeProfit    = (float?)action.TakeProfit,
                            Magic         = action.OrderId,
                            ExpertComment =
                                MarketOrder.MakeSignalComment(
                                    action.ServiceId),
                            MasterOrder = action.OrderId
                        };

                        try
                        {
                            var status =
                                ProxyTrade.SendNewOrderRequest(ProtectedOperationContext.MakeServerSideContext(),
                                                               action.OrderId, order, OrderType.Market,
                                                               (decimal)action.Price, 0);

                            if (signalRecord.subscriberAccountProcessingStatus.ContainsKey(order.AccountID))
                            {
                                Logger.ErrorFormat("Сигнал {0} - повторная отправка на счет {1}",
                                                   action, order.AccountID);
                            }
                            else
                            {
                                signalRecord.subscriberAccountProcessingStatus[order.AccountID] = status;
                            }

                            if (status != RequestStatus.OK)
                            {
                                Logger.ErrorFormat("ProcessSignalOpenOrder - ошибка обработки сервером" +
                                                   " запроса SendNewOrderRequest, master order: {0}, account: {1}, {2}",
                                                   action.OrderId, sub.TargetAccount, status);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat(
                                "ProcessSignalOpenOrder - ошибка отправки запроса SendNewOrderRequest, master order: {0}, account: {1}, {2}",
                                action.OrderId, sub.TargetAccount, ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.DebugFormat("ProcessSignalOpenOrder(#{0} - {1}) - исключение: {2}",
                                   action.OrderId, action.Ticker, ex);
            }
        }
Ejemplo n.º 6
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");
        }
Ejemplo n.º 7
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;
        }
Ejemplo n.º 8
0
        private static void ProcessSignalOpenOrder(TradeSignalActionTrade action)
        {
            try
            {
                var signalRecord = EnqueueProcessedSignalRecord(action);

                using (var ctx = DatabaseContext.Instance.Make())
                {
                    // получить информацию по настройкам торговых сигналов
                    var subscriptions = (from subsSig in ctx.SUBSCRIPTION_SIGNAL
                                         where (subsSig.AutoTrade ?? false) && subsSig.Service == action.ServiceId && subsSig.TargetAccount.HasValue
                                         select subsSig).ToList();

                    foreach (var sub in subscriptions)
                    {

                        var volm = sub.FixedVolume ?? 0;
                        if (volm == 0)
                            volm = GetNewOrderVolume(action, ctx, sub);

                        // объем входа недопустимо мал либо ошибка в расчете
                        if (volm == 0)
                            return;

                        var order = new MarketOrder
                        {
                            // ReSharper disable PossibleInvalidOperationException
                            AccountID = sub.TargetAccount.Value,
                            // ReSharper restore PossibleInvalidOperationException
                            Volume = volm,
                            Side = action.Side,
                            Symbol = action.Ticker,
                            StopLoss = (float?)action.StopLoss,
                            TakeProfit = (float?)action.TakeProfit,
                            Magic = action.OrderId,
                            ExpertComment =
                                MarketOrder.MakeSignalComment(
                                    action.ServiceId),
                            MasterOrder = action.OrderId
                        };

                        try
                        {
                            var status =
                                ProxyTrade.SendNewOrderRequest(ProtectedOperationContext.MakeServerSideContext(),
                                                               action.OrderId, order, OrderType.Market,
                                                               (decimal)action.Price, 0);

                            if (signalRecord.subscriberAccountProcessingStatus.ContainsKey(order.AccountID))
                                Logger.ErrorFormat("Сигнал {0} - повторная отправка на счет {1}",
                                    action, order.AccountID);
                            else
                                signalRecord.subscriberAccountProcessingStatus[order.AccountID] = status;

                            if (status != RequestStatus.OK)
                                Logger.ErrorFormat("ProcessSignalOpenOrder - ошибка обработки сервером" +
                                                   " запроса SendNewOrderRequest, master order: {0}, account: {1}, {2}",
                                                   action.OrderId, sub.TargetAccount, status);
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat(
                                "ProcessSignalOpenOrder - ошибка отправки запроса SendNewOrderRequest, master order: {0}, account: {1}, {2}",
                                action.OrderId, sub.TargetAccount, ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.DebugFormat("ProcessSignalOpenOrder(#{0} - {1}) - исключение: {2}",
                    action.OrderId, action.Ticker, ex);
            }
        }
        private void MakeSignalNewDeal(
            int accountId, 
            string ticker,
            int side,
            int volume,
            decimal? stopLoss, 
            decimal? takeProfit,
            int orderId,
            float priceEnter)
        {
            // разослать сигнал подписчикам?
            var signalCat = ManagementTraderList.Instance.IsSignaller(accountId);
            if (!signalCat.HasValue) return;
            Logger.InfoFormat("MakeSignalNewDeal (cat={0})", signalCat);

            // посчитать плечо сделки
            var leverage = CalculateDealLeverage(accountId, ticker, volume);
            if (leverage == null)
            {
                Logger.InfoFormat("MakeSignalNewDeal({0}, {1}, {2}, {3}) - leverage is null",
                    accountId, ticker, side, volume);
                return;
            }

            // таки разослать
            var action = new TradeSignalActionTrade
            {
                ServiceId = signalCat.Value,
                Price = priceEnter,
                Side = side,
                Ticker = ticker,
                StopLoss = stopLoss ?? 0,
                TakeProfit = takeProfit ?? 0,
                OrderId = orderId,
                Leverage = leverage.Value
            };

            Logger.InfoFormat("MakeSignalNewDeal({0}, {1}, {2}, {3}) - sending signal (leverage is {4:f2})",
                    accountId, ticker, side, volume, leverage.Value);
            ServiceManagerClientManagerProxy.Instance.ProcessTradeSignalAction(action);
        }