Exemple #1
0
        private bool _er_Update(ExecutionReport er, FixOrderStatus ordS, string desc, string bolsa)
        {
            try
            {
                int account;
                if (bolsa.Equals(ExchangePrefixes.BOVESPA, StringComparison.InvariantCultureIgnoreCase))
                {
                    string acc = er.Account.getValue();
                    acc     = (acc.Remove(acc.Length - 1));
                    account = Convert.ToInt32(acc);
                }
                else
                {
                    account = Convert.ToInt32(er.Account.getValue());
                }

                // Buscar Ordem Original, de algum jeito!!!
                // 1a. tentativa: Tentar via ExchangeNumber
                // 2a. tentativa: Tentar via ClOrdID e OrigClOrdID
                // 3a. tentativa: Tentar via ClOrdID no tb_fix_order_update e buscar a ordem pelo OrderID
                // 4a. tentativa: ahhh foda-se, nao achou mesmo

                OrderDbInfo orderOrig = null;

                // 1a. tentativa
                if (er.IsSetOrderID() && !er.OrderID.getValue().Equals("NONE"))
                {
                    orderOrig = _db.BuscarOrdemPorExchangeNumber(er.OrderID.getValue());
                }
                // 2a. Tentativa
                if (null == orderOrig || orderOrig.OrderID == 0)
                {
                    orderOrig = _db.BuscarOrdem(er.ClOrdID.getValue(), account, er.Symbol.getValue());
                    if (orderOrig.OrderID == 0)
                    {
                        // Se ordem nao encontrada, entao procurar pelo OrigClOrdID
                        if (er.IsSetOrigClOrdID())
                        {
                            orderOrig = _db.BuscarOrdem(er.OrigClOrdID.getValue(), account, er.Symbol.getValue());
                            if (orderOrig.OrderID == 0)
                            {
                                orderOrig = _db.BuscarOrdem(er.OrigClOrdID.getValue(), account, er.Symbol.getValue(), true);
                                //if (orderOrig.OrderID == 0)
                                //{
                                //    logger.Info("01 ER - Nao achou a ordem em questao!!!: " + er.OrigClOrdID.getValue() + " Status: " + ordS.ToString() + " Desc: " + desc);
                                //    return false;
                                //}
                            }
                            else
                            {
                                orderOrig = _db.BuscarOrdem(er.OrigClOrdID.getValue(), account, er.Symbol.getValue());
                            }
                        }
                        else
                        {
                            orderOrig = _db.BuscarOrdem(er.ClOrdID.getValue(), account, er.Symbol.getValue(), true);
                            //if (orderOrig.OrderID == 0)
                            //{
                            //    logger.Info("02 ER - Nao achou a ordem em questao!!!: " + er.ClOrdID.getValue() + " Status: " + ordS.ToString() + " Desc: " + desc);
                            //    return false;
                            //}
                        }
                    }
                }

                // 3a. Tentativa
                if (null == orderOrig || orderOrig.OrderID == 0)
                {
                    // Buscar a partir de tb_fix_order_update
                    OrderDbUpdateInfo orderUpdate = _db.BuscarOrdemUpdate(er.ClOrdID.getValue());
                    // Buscar ordem original a partir do order ID
                    if (orderUpdate.OrderID != 0)
                    {
                        orderOrig = _db.BuscarOrdemPorOrderID(orderUpdate.OrderID);
                    }
                    else
                    {
                        logger.Info("01 ER - Nao achou a ordem em questao!!!: " + er.ClOrdID.getValue() + " Status: " + ordS.ToString() + " Desc: " + desc);
                        return(false);
                    }
                }
                if (null == orderOrig || orderOrig.OrderID == 0)
                {
                    logger.Info("02 ER - Nao achou a ordem em questao!!!: " + er.ClOrdID.getValue() + " Status: " + ordS.ToString() + " Desc: " + desc);
                    return(false);
                }
                //}
                //else
                //{
                //    orderOrig = _db.BuscarOrdemPorExchangeNumber(er.OrderID.getValue());
                //    if (orderOrig.OrderID == 0)
                //    {
                //        logger.Info("ER - Nao achou a ordem em questao via exchange number (OrderID ER)!!!: " + er.OrderID.getValue() + " Status: " + ordS.ToString() + " Desc: " + desc);
                //        return false;
                //    }
                // }
                // Adicionar OrdemDetalhe
                OrderDbDetalheInfo detail = new OrderDbDetalheInfo();
                detail.OrderID       = orderOrig.OrderID;
                detail.TransactID    = er.ExecID.getValue();
                detail.OrderQty      = Convert.ToInt32(er.OrderQty.getValue());
                detail.Price         = er.IsSetField(Tags.Price) ? er.Price.getValue() : Decimal.Zero;
                detail.OrderStatusID = (int)ordS;
                detail.TransactTime  = er.TransactTime.getValue();
                if (er.IsSetField(Tags.Text))
                {
                    detail.Description = desc + " - " + er.Text.getValue();
                }
                else
                {
                    detail.Description = desc;
                }

                detail.TradeQty     = er.IsSetField(Tags.LastQty) ? Convert.ToInt32(er.LastQty.getValue()) : 0;
                detail.CumQty       = er.IsSetField(Tags.CumQty) ? Convert.ToInt32(er.CumQty.getValue()) : 0;
                detail.FixMsgSeqNum = Convert.ToInt32(er.Header.GetField(Tags.MsgSeqNum));
                if (!_db.InserirOrdemDetalhe(detail, orderOrig.ClOrdID))
                {
                    logger.Info("Erro ao inserir o registro na tabela tb_fix_order_update");
                    return(false);
                }

                // Atualizar Ordem
                orderOrig.ExchangeNumberID = er.OrderID.getValue();
                orderOrig.OrdStatus        = (int)ordS;
                orderOrig.TransactTime     = er.TransactTime.getValue();
                // orderOrig.ClOrdID = er.ClOrdID.getValue();
                // if (er.IsSetOrigClOrdID())
                //    orderOrig.OrigClOrdID = er.OrigClOrdID.getValue();
                if (er.IsSetField(Tags.LeavesQty))
                {
                    orderOrig.OrderQtyRemaining = Convert.ToInt32(er.LeavesQty.getValue());
                }
                if (er.IsSetField(Tags.CumQty))
                {
                    orderOrig.CumQty = Convert.ToInt32(er.CumQty.getValue());
                }
                orderOrig.Memo = er.IsSetField(Tags.Memo) ? er.GetField(Tags.Memo): string.Empty;
                if (!_db.AtualizarOrdem(orderOrig))
                {
                    logger.Info("Problemas na atualizacao da ordem. ClOrdID: " + orderOrig.ClOrdID);
                    return(false);
                }

                DropCopyCallbackManager.Instance.EnqueueCallback(orderOrig);

                return(true);
            }
            catch (Exception ex)
            {
                logger.Error("_er_Update: Erro na atualizacao dos status da ordem: " + ex.Message, ex);
                return(false);
            }
        }
        private async void Handle(ExecutionReport msg)
        {
            var    clOrderId     = msg.ClOrdID.Obj;
            string origClOrderId = null;

            if (msg.IsSetOrigClOrdID())
            {
                origClOrderId = msg.OrigClOrdID.Obj;
            }

            var state = msg.IsSetOrdStatus() ? ConvertOrderState(msg.OrdStatus) : null;
            var price = msg.IsSetPrice() ? msg.Price.Obj : (decimal?)null;

            price = price != 0M ? price : null;
            var qty             = msg.IsSetOrderQty() ? (uint)msg.OrderQty.Obj : (uint?)null;
            var filledQty       = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null;
            var activeQty       = msg.IsSetLeavesQty() ? (uint)msg.LeavesQty.Obj : (uint?)null;
            var time            = msg.IsSetTransactTime() ? ParseTransactTime() : DateTime.Now;
            var orderExchangeId = msg.IsSetOrderID() ? msg.OrderID.Obj : null;

            var transactionId = _orders.GetOrCreateOrderTransactionId(origClOrderId ?? clOrderId);

            var oscm = new OrderStateChangeMessage
            {
                TransactionId   = transactionId,
                State           = state,
                Price           = price,
                Quantity        = qty,
                FilledQuantity  = filledQty,
                ActiveQuantity  = activeQty,
                ChangeTime      = time,
                OrderExchangeId = orderExchangeId
            };

            switch (msg.ExecType.Obj)
            {
            case ExecType.NEW:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                break;

            case ExecType.TRADE:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);

                SendMessage(oscm);
                await EmitFillAsync();

                if (oscm.State == OrderState.Filled)
                {
                    _newOrderTransactions.Forget(transactionId);
                    _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                    _orders.ForgetOrder(transactionId);
                }
                break;

            case ExecType.FILL:
                _newOrderTransactions.Accept(clOrderId);

                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                await EmitFillAsync();

                if (oscm.State == OrderState.Filled)
                {
                    _newOrderTransactions.Forget(transactionId);
                    _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                    _orders.ForgetOrder(transactionId);
                }
                break;

            case ExecType.PARTIAL_FILL:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                await EmitFillAsync();

                break;

            case ExecType.REJECTED:
                string rejectReason;
                switch (msg.OrdRejReason.Obj)
                {
                case OrdRejReason.UNKNOWN_SYMBOL:
                    rejectReason = "Unknown symbol";
                    break;

                case OrdRejReason.EXCHANGE_CLOSED:
                    rejectReason = "Exchange closed";
                    break;

                case OrdRejReason.ORDER_EXCEEDS_LIMIT:
                    rejectReason = "Order exceeds limit";
                    break;

                case OrdRejReason.DUPLICATE_ORDER:
                    rejectReason = "Duplicate order";
                    break;

                default:
                    rejectReason = $"#{msg.OrdRejReason.Obj}";
                    break;
                }
                if (!string.IsNullOrEmpty(msg.Text?.Obj))
                {
                    rejectReason = $"{rejectReason}. {msg.Text?.Obj}";
                }
                _newOrderTransactions.Reject(clOrderId, rejectReason);
                _orders.ForgetOrder(transactionId);
                break;

            case ExecType.PENDING_CANCEL:
                _killOrderTransactions.Accept(msg.ClOrdID.Obj);
                SendMessage(oscm);
                break;

            case ExecType.CANCELED:
                _killOrderTransactions.Accept(msg.ClOrdID.Obj);
                _newOrderTransactions.Forget(transactionId);
                _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                _orders.ForgetOrder(transactionId);
                SendMessage(oscm);
                break;

            case ExecType.PENDING_REPLACE:
                _modifyOrderTransactions.Accept(clOrderId);
                break;

            case ExecType.REPLACED:
                _newOrderTransactions.Forget(origClOrderId);
                _killOrderTransactions.Forget(clOrderId);
                _orders.UpdateOrderParams(
                    orderExchangeId: orderExchangeId,
                    origClOrderId: origClOrderId,
                    clOrderId: clOrderId,
                    symbol: msg.Symbol.Obj,
                    qty: msg.OrderQty.Obj,
                    side: msg.Side.Obj);

                SendMessage(oscm);
                break;

            default:
                _Log.Warn().PrintFormat("Unknown ExecType: {0}", msg.ExecType.Obj);
                break;
            }

            OrderState?ConvertOrderState(OrdStatus field)
            {
                switch (field.Obj)
                {
                case OrdStatus.PENDING_NEW: return(OrderState.New);

                case OrdStatus.NEW: return(OrderState.Active);

                case OrdStatus.CANCELED: return(OrderState.Cancelled);

                case OrdStatus.FILLED: return(OrderState.Filled);

                case OrdStatus.PARTIALLY_FILLED: return(OrderState.PartiallyFilled);

                case OrdStatus.REJECTED: return(OrderState.Error);

                case OrdStatus.PENDING_CANCEL: return(null);

                case OrdStatus.PENDING_REPLACE: return(null);

                default:
                    _Log.Warn().PrintFormat("Unknown OrdStatus: {0}", field.Obj);
                    return(null);
                }
            }

            DateTime ParseTransactTime()
            {
                var maxLen = "20170912-09:39:57.2761221".Length;

                var str = msg.GetString(60 /*TransactTime*/);

                if (str.Length > maxLen)
                {
                    str = str.Substring(0, maxLen);
                }
                var t = DateTime.ParseExact(str, "yyyyMMdd-HH:mm:ss.fffffff", null, DateTimeStyles.AssumeUniversal);

                return(t);
            }

            async Task EmitFillAsync()
            {
                if (!msg.IsSetSecondaryExecID())
                {
                    return;
                }

                var fillExchangeId = msg.SecondaryExecID.Obj;
                var fillPrice      = msg.IsSetLastPx() ? msg.LastPx.Obj : (decimal?)null;

                price = price != 0M ? price : null;
                var fillQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null;

                if (fillPrice == null || fillQty == null)
                {
                    return;
                }

                Instrument instrument;

                try
                {
                    instrument = await _settings.InstrumentConverter.ResolveSymbolAsync(this, msg.Symbol.Obj);
                }
                catch (Exception e)
                {
                    _Log.Error().Print(e, $"Failed to resolve instrument {msg.Symbol.Obj}");
                    return;
                }

                var fill = new FillMessage
                {
                    Price           = fillPrice.Value,
                    Quantity        = fillQty.Value,
                    DateTime        = time,
                    Instrument      = instrument,
                    Account         = msg.Account.Obj,
                    Operation       = msg.Side.Obj == Side.BUY ? OrderOperation.Buy : OrderOperation.Sell,
                    ExchangeId      = fillExchangeId,
                    ExchangeOrderId = orderExchangeId
                };

                SendMessage(fill);
            }
        }
Exemple #3
0
        /// <summary>
        /// Validar os estados da ordem e executar as respectivas operacoes no dicionario de mensagens
        /// (Mensagens de Execution Report - ER)
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="eType"></param>
        /// <param name="oStatus"></param>
        /// <param name="dic"></param>
        /// Retorna o TOORderSession referente ao Execution Report
        /// OBS: strChave - no momento esta considerando sempre clOrdID
        public void VerifyOrderSituationER(ExecutionReport msg, char e, char o, SessionID ss,
                                           OrderSessionManager dic, string strChave, out TOOrderSession ord)

        {
            ord = null;
            try
            {
                string strOrigClChave     = string.Empty;
                string strExchNumberChave = msg.OrderID.ToString() + "-" + msg.Account.ToString() + "-" + msg.Symbol.ToString();
                if (null != ss)// Registry found
                {
                    // Atualiza o TO com o ExchangeNumber (Tag 37, order ID)
                    TOOrderSession aux = null;
                    dic.GetOrder(strChave, out aux);
                    if (null != aux)
                    {
                        aux.ExchangeNumberID = strExchNumberChave;
                    }

                    // New Order, Exec: New, OrdStatus: New - nao faz nada, somente retorna o TOOrderSession correspondente
                    if (e == ExecType.NEW && o == OrdStatus.NEW)
                    {
                        // Por ser new order, nao se aplica fazer busca pelo exchange number id
                        // pois ainda não foi atualizado
                        dic.GetOrder(strChave, out ord);
                        //ord.ExchangeNumberID = msg.OrderID.getValue() + "-" + msg.Account.getValue() + "-" + msg.Symbol.getValue();
                    }
                    // Retornar o TOOrderSession correspondente para
                    if (o == OrdStatus.FILLED || o == OrdStatus.PARTIALLY_FILLED)
                    {
                        dic.GetOrder(strChave, out ord, strExchNumberChave);
                        //ord.ExchangeNumberID = msg.OrderID.getValue() + "-" + msg.Account.getValue() + "-" + msg.Symbol.getValue();
                    }

                    // Stop Order Entry, Exec: New, OrdStatus: New - nao faz nada
                    // No request stop order trigger, Exec: New, OrdStatus: New - nao faz nada
                    // Order with on close, Exec: New, OrdStatus: New
                    // Order with on close attribute is activated when the closing auction starts, Exec: New, Order: New
                    // MinQty order entry, not enough quantity, Exec: new, Order: new

                    // New Order, Exec: Rejected, OrdStatus: Rejected - excluir a chave
                    // New Order, Exec: Suspended, OrdStatus: Suspended
                    // No request, Exec: Trade, OrdStatus: Filled
                    if ((e == ExecType.REJECTED && o == OrdStatus.REJECTED) ||
                        (e == ExecType.SUSPENDED && o == OrdStatus.SUSPENDED) ||
                        (e == ExecType.TRADE && o == OrdStatus.FILLED) ||
                        (e == ExecType.EXPIRED && o == OrdStatus.EXPIRED))
                    {
                        lock (dic)
                        {
                            TOOrderSession toOS = null;
                            int            ret  = dic.GetOrder(strChave, out toOS, strExchNumberChave);
                            ord  = toOS;
                            toOS = null;
                            if (ret == FindType.EXCHANGE_NUMBER)
                            {
                                dic.RemoveOrder(ord.ChaveDicionario);
                            }
                            else
                            {
                                dic.RemoveOrder(strChave);
                            }
                        }
                    }
                    // Order Modify, Exec: Replace, OrdStatus: Replaced
                    if (e == ExecType.REPLACE && o == OrdStatus.REPLACED)
                    {
                        strOrigClChave = msg.OrigClOrdID.ToString() + "-" + msg.Account.ToString() + "-" + msg.Symbol.ToString();
                        lock (dic)
                        {
                            //if (dic.ExistOrder(strOrigClChave))
                            //{
                            TOOrderSession toOS = null;
                            int            ret  = dic.GetOrder(strOrigClChave, out toOS, strExchNumberChave, KeyType.ORIGCLORDID);
                            ord  = toOS;
                            toOS = null;
                            if (ret == FindType.EXCHANGE_NUMBER)
                            {
                                dic.RemoveOrder(ord.ChaveDicionario);
                            }
                            else
                            {
                                dic.RemoveOrder(strOrigClChave);
                            }
                            //}
                        }
                    }
                    // Cancelation, Exec: Cancelled, OrdStatus: Cancelled
                    // No request FAK Partially Filled, Exec: Canceled, OrdStatus: Canceled
                    // No request FOK Partially Filled, Exec: Canceled, OrdStatus: Canceled
                    // MinQty order entry, not enough quantity  rejected, Exec: Cancelled, Order: Cancelled
                    if (e == ExecType.CANCELED && o == OrdStatus.CANCELED)
                    {
                        bool processOrig = true;
                        // Tratamento de outros tipos de timeinforce (para execucao e cancelamento, o orig clord id não é fornecido)
                        if (msg.IsSetField(Tags.TimeInForce))
                        {
                            switch (msg.TimeInForce.getValue())
                            {
                            case TimeInForce.IMMEDIATE_OR_CANCEL:
                            case TimeInForce.FILL_OR_KILL:
                                processOrig    = false;
                                strOrigClChave = msg.ClOrdID.ToString() + "-" + msg.Account.ToString() + "-" + msg.Symbol.ToString();
                                break;

                            default:
                            {
                                // Caso o cancelamento tenha partido da bolsa, tambem nao eh fornecido o OrigClOrdID
                                // entao tenta-se utilizar o ClOrdID vindo do ExecutionReport
                                string aux1 = msg.IsSetOrigClOrdID() ? msg.OrigClOrdID.ToString() : msg.ClOrdID.ToString();
                                strOrigClChave = aux1 + "-" + msg.Account.ToString() + "-" + msg.Symbol.ToString();
                            }
                            break;
                            }
                        }
                        else
                        {
                            // TimeInForce = 0 (DAY) - Default
                            // Caso o Orig nao esteja na mensagem, tenta-se buscar pelo ClOrdID
                            string aux1 = msg.IsSetOrigClOrdID() ? msg.OrigClOrdID.ToString() : msg.ClOrdID.ToString();
                            strOrigClChave = aux1 + "-" + msg.Account.ToString() + "-" + msg.Symbol.ToString();
                        }
                        lock (dic)
                        {
                            TOOrderSession toOS = null;
                            int            ret  = 0;
                            ret = dic.GetOrder(strOrigClChave, out toOS, strExchNumberChave, KeyType.ORIGCLORDID);
                            if (null != toOS)
                            {
                                ord  = toOS;
                                toOS = null;
                                if (ret == FindType.EXCHANGE_NUMBER)
                                {
                                    dic.RemoveOrder(ord.ChaveDicionario);
                                }
                                else
                                {
                                    dic.RemoveOrder(strOrigClChave);
                                }
                            }
                            if (processOrig)
                            {
                                ret = dic.GetOrder(strChave, out toOS, strExchNumberChave);
                                if (ret == FindType.EXCHANGE_NUMBER)
                                {
                                    dic.RemoveOrder(toOS.ChaveDicionario);
                                }
                                else
                                {
                                    dic.RemoveOrder(strChave);
                                }
                                toOS = null;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error("VerifyOrderSituationER(): " + ex.Message, ex);
            }
        }