Esempio n. 1
0
        /// <summary>
        /// Редактирование 'опасных' полей сделок
        /// </summary>
        /// <param name="strId">Уникальные идентификаторы редактируемых сделок</param>
        /// <param name="currentState">Статус редактируемых сделок</param>
        /// <param name="newTicker">Новое значение инструмента</param>
        /// <param name="newSide">Новое значение типа сделки</param>
        /// <param name="newVolume">Новое значение объёма сделки</param>
        /// <param name="newEnterPrice">Новое значение цены входа</param>
        /// <param name="newExitPrice">Новое значение цены выхода</param>
        public bool EditDangerDeal(string strId, PositionState currentState, string newTicker, int?newSide, int?newVolume, float?newEnterPrice, float?newExitPrice)
        {
            var id = strId.ToIntArrayUniform();

            using (var ctx = DatabaseContext.Instance.Make())
            {
                var selOrders = new List <MarketOrder>();
                // ReSharper disable LoopCanBeConvertedToQuery
                if (currentState == PositionState.Closed)
                {
                    foreach (var order in ctx.POSITION_CLOSED.Where(x => id.Contains(x.ID)))
                    {
                        selOrders.Add(LinqToEntity.DecorateOrder(order));
                    }
                }
                else
                {
                    foreach (var order in ctx.POSITION.Where(x => id.Contains(x.ID)))
                    {
                        selOrders.Add(LinqToEntity.DecorateOrder(order));
                    }
                }
                // ReSharper restore LoopCanBeConvertedToQuery

                // Группируем все сделки по счётам
                var selOrderGroupByAccount = selOrders.GroupBy(x => x.AccountID);
                // Идём по счетам в группе
                foreach (var selOrderGroup in selOrderGroupByAccount)
                {
                    var acc = accountRepository.GetAccount(selOrderGroup.Key);

                    try
                    {
                        // Идём по сделкам в счёте
                        foreach (var order in selOrderGroup)
                        {
                            decimal?sl = null;
                            if (order.StopLoss.HasValue)
                            {
                                sl = Convert.ToDecimal(order.StopLoss);
                            }

                            decimal?tp = null;
                            if (order.TakeProfit.HasValue)
                            {
                                tp = Convert.ToDecimal(order.TakeProfit);
                            }

                            var timeEnter = order.TimeEnter;
                            var timeExit  = order.TimeExit;
                            var price     = newEnterPrice.HasValue ? newEnterPrice : order.PriceEnter;
                            var priceExit = newExitPrice.HasValue ? newExitPrice : order.PriceExit;
                            var volume    = newVolume.HasValue ? newVolume : order.Volume;
                            var symbol    = !string.IsNullOrEmpty(newTicker) && newTicker.ToLower() != "null" ? newTicker : order.Symbol;
                            var side      = newSide.HasValue ? newSide : order.Side;
                            var state     = order.State;
                            #region

                            MarketOrder ordClosed = null;
                            if (state == PositionState.Closed)
                            {
                                // посчитать профит по сделке
                                ordClosed           = order.MakeCopy();
                                ordClosed.State     = PositionState.Closed;
                                ordClosed.PriceExit = priceExit.Value;
                                ordClosed.TimeExit  = timeExit.Value;
                                string errorStr = null;
                                if (!priceExit.HasValue || !DealProfitCalculator.CalculateOrderProfit(ordClosed, acc.Currency, priceExit.Value, out errorStr))
                                {
                                    if (!string.IsNullOrEmpty(errorStr))
                                    {
                                        Logger.Error("Сделка " + order.ID + " не будет закрыта : " + errorStr);
                                    }
                                    else
                                    {
                                        Logger.Error("Сделка " + order.ID + ". не будет закрыта : не указана priceExit.");
                                    }
                                    continue;
                                }
                            }

                            try
                            {
                                //Если сделка из 'открытых'
                                if (state != PositionState.Closed)
                                {
                                    // поправить открытую позицию
                                    var pos = ctx.POSITION.First(p => p.ID == order.ID);
                                    pos.PriceEnter = Convert.ToDecimal(price.Value);
                                    pos.TimeEnter  = timeEnter;
                                    pos.Stoploss   = sl;
                                    pos.Takeprofit = tp;
                                    pos.Volume     = volume.Value;
                                    pos.Symbol     = symbol;
                                    pos.Side       = side.Value;
                                    pos.State      = (int)state;
                                }
                                else
                                {
                                    #region поправить закрытую позу и скорректировать результат

                                    var pos = ctx.POSITION_CLOSED.First(p => p.ID == order.ID);
                                    pos.PriceEnter   = Convert.ToDecimal(price.Value);
                                    pos.TimeEnter    = timeEnter;
                                    pos.Stoploss     = sl;
                                    pos.Takeprofit   = tp;
                                    pos.Volume       = volume.Value;
                                    pos.Symbol       = symbol;
                                    pos.Side         = side.Value;
                                    pos.PriceExit    = Convert.ToDecimal(priceExit.Value);
                                    pos.TimeExit     = timeExit.Value;
                                    pos.ResultDepo   = (decimal)ordClosed.ResultDepo;
                                    pos.ResultBase   = (decimal)ordClosed.ResultBase;
                                    pos.ResultPoints = (decimal)ordClosed.ResultPoints;

                                    #endregion

                                    // поправить проводку и баланс
                                    UpdateBalanceChange(ctx, ordClosed, false);
                                }
                            }
                            catch (Exception ex)
                            {
                                Logger.Error("Ошибка при редактировании сделки " + order.ID, ex);
                            }
                            #endregion

                            Logger.Info("Сделка " + order.ID + " отредактирована удачно.");
                        }
                        // коммит
                        ctx.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("EditDangerDeal", ex);
                        return(false);
                    }

                    if (currentState == PositionState.Closed)
                    {
                        ReCalculateAccountBalance(ctx, acc.ID);
                    }
                }
                return(true);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Закрытие сделок
        /// </summary>
        /// <param name="strId">Уникальные идентификаторы закрываемых сделок, перечисленные через запятую</param>
        /// <param name="timeExit">Время выхода</param>
        /// <param name="exitReason">Symbol, Side (в виде Ask и Bid), Price</param>
        /// <param name="lstPrice">Причина закрытия сделки, указанная пользователем</param>
        public List <string> ClosingPositions(string strId, DateTime timeExit, PositionExitReason exitReason, List <Tuple <string, int, float> > lstPrice)
        {
            Logger.Info("Начинаем закрывать сделки " + strId);

            var result = new List <string>();
            var id     = strId.ToIntArrayUniform();

            try
            {
                using (var ctx = DatabaseContext.Instance.Make())
                {
                    // Вытаскиваем все открытые сделки, которые нужно закрыть
                    var selOrders = new List <MarketOrder>();
                    // ReSharper disable LoopCanBeConvertedToQuery
                    foreach (var order in ctx.POSITION.Where(x => id.Contains(x.ID)))
                    {
                        selOrders.Add(LinqToEntity.DecorateOrder(order));
                    }
                    // ReSharper restore LoopCanBeConvertedToQuery

                    if (selOrders.Count != id.Length)
                    {
                        Logger.Error("ClosingPositions() - в таблице 'POSITION' не найдены некоторые или все сделки с идентификаторами " + strId);
                    }

                    // Группируем все сделки по счётам
                    var selOrderGroupByAccount = selOrders.GroupBy(x => x.AccountID);

                    // Перебираем все счета
                    foreach (var orderGroup in selOrderGroupByAccount)
                    {
                        // Список удачно закрытых сделок в текущем счёте
                        var successClosedPositions = new List <string>();

                        var acc = accountRepository.GetAccount(orderGroup.Key);
                        if (acc == null)
                        {
                            Logger.Error("ClosingPositions() - не удалось получить счёт " + orderGroup.Key);
                            continue;
                        }

                        Logger.Info("Начинаем закрывать сделки в счёте " + orderGroup.Key);
                        // Перебираем все сделки в текущем счёте
                        foreach (var order in orderGroup)
                        {
                            #region
                            //Ищем цену выхода, указанную пользователем, для сделок с таким тикером и направлением
                            var priceExitTuple = lstPrice.FirstOrDefault(x => x.Item1 == order.Symbol && x.Item2 == order.Side);

                            if (priceExitTuple == null)
                            {
                                Logger.Error(string.Format("ClosingPositions() - не найдена цена выхода, указанная пользователем, для сделок счёта {0} с тикером {1} и направлением {2}",
                                                           order.ID, order.Symbol, order.Side)); continue;
                            }

                            var closedOrder = order.MakeCopy();
                            closedOrder.State      = PositionState.Closed;
                            closedOrder.TimeExit   = timeExit;
                            closedOrder.PriceExit  = priceExitTuple.Item3;
                            closedOrder.ExitReason = exitReason;

                            // посчитать прибыль
                            string errorStr;
                            if (!DealProfitCalculator.CalculateOrderProfit(closedOrder, acc.Currency, priceExitTuple.Item3, out errorStr))
                            {
                                if (!string.IsNullOrEmpty(errorStr))
                                {
                                    Logger.Error("Сделка " + closedOrder.ID + " не будет закрыта - не удалось пересчитать прибыль : " + errorStr);
                                }
                                continue;
                            }

                            var balance = new BALANCE_CHANGE
                            {
                                AccountID   = order.AccountID,
                                ChangeType  = closedOrder.ResultBase > 0 ? (int)BalanceChangeType.Profit : (int)BalanceChangeType.Loss,
                                Description = string.Format("результат сделки #{0}", order.ID),
                                Amount      = (decimal)Math.Abs(closedOrder.ResultDepo),
                                ValueDate   = closedOrder.TimeExit.Value
                            };

                            // убрать сделку из числа открытых, добавить закрытую и добавить проводку по счету
                            try
                            {
                                // убрать
                                var pos = ctx.POSITION.FirstOrDefault(p => p.ID == order.ID);
                                ctx.POSITION.Remove(pos);
                                Logger.Info("запись о сделке " + order.ID + " удалена из таблици POSITION");

                                ctx.POSITION_CLOSED.Add(LinqToEntity.UndecorateClosedPosition(closedOrder));
                                Logger.Info("запись о сделке " + order.ID + " добавленав таблицу POSITION_CLOSED");

                                // добавить проводку по счету
                                ctx.BALANCE_CHANGE.Add(balance);
                                var acBase = ctx.ACCOUNT.FirstOrDefault(ac => ac.ID == order.AccountID);

                                if (acBase == null)
                                {
                                    Logger.Error("ClosingPositions() - не удалось найти счёт " + order.AccountID + " в таблице 'ACCOUNT', что бы добавить проводку");
                                    continue;
                                }

                                acBase.Balance += (decimal)closedOrder.ResultDepo;
                                Logger.Info("Баланс счёта " + order.AccountID + " изменён на величину " + (decimal)closedOrder.ResultDepo);
                            }
                            catch (Exception ex)
                            {
                                Logger.Error("ClosingPositions() - Ошибка при попытке убрать сделку из числа открытых, добавить закрытую и добавить проводку по счету", ex);
                                continue;
                            }
                            #endregion
                            successClosedPositions.Add(order.ID.ToString());
                            Logger.Error("Сделка " + order.ID + " отредактирована удачно");
                        }
                        ReCalculateAccountBalance(ctx, acc.ID);

                        Logger.Info("Начинаем сохранять в базу данных изменения по счёту " + orderGroup.Key);
                        ctx.SaveChanges();
                        result.AddRange(successClosedPositions);
                    }

                    if (result.Count == 0)
                    {
                        Logger.Info("Не удалось закрыть ни одной из указанных сделок");
                    }
                    else
                    {
                        Logger.Info("Изменения сохранены. Из указанных сделок " + strId + " закрыты следующие: " + string.Join(", ", result));
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("ClosingPositions() - возникла ошибка при попытке сохранить изменения в базу данных. Не удалось закрыть сделки " + strId, ex);
            }
            return(result);
        }