public ExecutionReport ToOrderStatusUpdate(TradeExecutionUpdate eu)
        {
            var instrument      = ExchangeSymbolToLykkeInstrument(eu.AssetPair);
            var transactionTime = eu.TimeStamp;
            var tradeType       = ConvertTradeType(eu.Volume);
            var orderId         = eu.OrderId.ToString();

            return(new ExecutionReport(instrument, transactionTime, eu.Price, eu.Volume, tradeType, orderId, OrderExecutionStatus.Fill)
            {
                Message = eu.OrderType,
                Fee = eu.Fee,
                ExecType = ExecType.Trade
            });
        }
        public ExecutionReport ToOrderStatusUpdate(TradeExecutionUpdate eu)
        {
            var instrument      = ExchangeSymbolToLykkeInstrument(eu.AssetPair);
            var transactionTime = eu.TimeStamp;
            var tradeType       = ConvertTradeType(eu.Volume);
            var orderId         = eu.OrderId;

            return(new ExecutionReport(instrument, transactionTime, eu.OrderPrice ?? 0 /*could it be 0 when its a market order?*/, eu.Volume /*we set status to Fill, hence original and executed amount should be equal*/, eu.Volume, tradeType, orderId, OrderStatus.Fill, eu.OrderType, eu.Price)
            {
                Message = eu.OrderType,
                Fee = eu.Fee,
                ExecType = ExecType.Trade
            });
        }
        private void EmitFillOrder(TradeExecutionUpdate update)
        {
            try
            {
                var brokerId = update.OrderId.ToStringInvariant();

                var order = CachedOrderIDs
                            .FirstOrDefault(o => o.Value.BrokerId.Contains(brokerId))
                            .Value;

                if (order == null)
                {
                    order = _algorithm.Transactions.GetOrderByBrokerageId(brokerId);
                    if (order == null)
                    {
                        Log.Error($"EmitFillOrder(): order not found: BrokerId: {brokerId}");
                        return;
                    }
                }

                var symbol       = _symbolMapper.GetLeanSymbol(update.Symbol, SecurityType.Crypto, Market.Bitfinex);
                var fillPrice    = update.ExecPrice;
                var fillQuantity = update.ExecAmount;
                var direction    = fillQuantity < 0 ? OrderDirection.Sell : OrderDirection.Buy;
                var updTime      = Time.UnixMillisecondTimeStampToDateTime(update.MtsCreate);
                var orderFee     = new OrderFee(new CashAmount(Math.Abs(update.Fee), GetLeanCurrency(update.FeeCurrency)));

                var status = OrderStatus.Filled;
                if (fillQuantity != order.Quantity)
                {
                    decimal totalFillQuantity;
                    _fills.TryGetValue(order.Id, out totalFillQuantity);
                    totalFillQuantity += fillQuantity;
                    _fills[order.Id]   = totalFillQuantity;

                    status = totalFillQuantity == order.Quantity
                        ? OrderStatus.Filled
                        : OrderStatus.PartiallyFilled;
                }

                if (_algorithm.BrokerageModel.AccountType == AccountType.Cash &&
                    order.Direction == OrderDirection.Buy)
                {
                    // fees are debited in the base currency, so we have to subtract them from the filled quantity
                    fillQuantity -= orderFee.Value.Amount;

                    orderFee = new ModifiedFillQuantityOrderFee(orderFee.Value);
                }

                var orderEvent = new OrderEvent
                                 (
                    order.Id, symbol, updTime, status,
                    direction, fillPrice, fillQuantity,
                    orderFee, $"Bitfinex Order Event {direction}"
                                 );

                // if the order is closed, we no longer need it in the active order list
                if (status == OrderStatus.Filled)
                {
                    Order outOrder;
                    CachedOrderIDs.TryRemove(order.Id, out outOrder);

                    decimal ignored;
                    _fills.TryRemove(order.Id, out ignored);

                    var clientOrderId = _orderMap.FirstOrDefault(x => x.Value.BrokerId.Contains(brokerId)).Key;
                    if (clientOrderId > 0)
                    {
                        _orderMap.TryRemove(clientOrderId, out outOrder);
                    }
                }

                OnOrderEvent(orderEvent);
            }
            catch (Exception e)
            {
                Log.Error(e);
                throw;
            }
        }
        private void EmitFillOrder(TradeExecutionUpdate update)
        {
            try
            {
                var brokerId = update.OrderId.ToStringInvariant();

                var order = CachedOrderIDs
                            .FirstOrDefault(o => o.Value.BrokerId.Contains(brokerId))
                            .Value;

                if (order == null)
                {
                    order = _algorithm.Transactions.GetOrderByBrokerageId(brokerId);
                    if (order == null)
                    {
                        Log.Error($"BitfinexBrokerage.EmitFillOrder(): order not found: BrokerId: {brokerId}");
                        return;
                    }
                }

                var symbol       = _symbolMapper.GetLeanSymbol(update.Symbol, SecurityType.Crypto, Market.Bitfinex);
                var fillPrice    = update.ExecPrice;
                var fillQuantity = update.ExecAmount;
                var direction    = fillQuantity < 0 ? OrderDirection.Sell : OrderDirection.Buy;
                var updTime      = Time.UnixMillisecondTimeStampToDateTime(update.MtsCreate);
                var orderFee     = new OrderFee(new CashAmount(Math.Abs(update.Fee), GetLeanCurrency(update.FeeCurrency)));

                var status = OrderStatus.Filled;
                if (fillQuantity != order.Quantity)
                {
                    decimal totalFillQuantity;
                    _fills.TryGetValue(order.Id, out totalFillQuantity);
                    totalFillQuantity += fillQuantity;
                    _fills[order.Id]   = totalFillQuantity;

                    status = totalFillQuantity == order.Quantity
                        ? OrderStatus.Filled
                        : OrderStatus.PartiallyFilled;
                }

                if (_algorithm.BrokerageModel.AccountType == AccountType.Cash &&
                    order.Direction == OrderDirection.Buy)
                {
                    var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market,
                                                                                         symbol,
                                                                                         symbol.SecurityType,
                                                                                         AccountBaseCurrency);
                    Crypto.DecomposeCurrencyPair(symbol, symbolProperties, out var baseCurrency, out var _);

                    if (orderFee.Value.Currency != baseCurrency)
                    {
                        OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, "UnexpectedFeeCurrency", $"Unexpected fee currency {orderFee.Value.Currency} for symbol {symbol}. OrderId {order.Id}. BrokerageOrderId {brokerId}. " +
                                                            "This error can happen because your account is Margin type and Lean is configured to be Cash type or while using Cash type the Bitfinex account fee settings are set to 'Asset Trading Fee' and should be set to 'Currency Exchange Fee'."));
                    }
                    else
                    {
                        // fees are debited in the base currency, so we have to subtract them from the filled quantity
                        fillQuantity -= orderFee.Value.Amount;

                        orderFee = new ModifiedFillQuantityOrderFee(orderFee.Value);
                    }
                }

                var orderEvent = new OrderEvent
                                 (
                    order.Id, symbol, updTime, status,
                    direction, fillPrice, fillQuantity,
                    orderFee, $"Bitfinex Order Event {direction}"
                                 );

                // if the order is closed, we no longer need it in the active order list
                if (status == OrderStatus.Filled)
                {
                    Order outOrder;
                    CachedOrderIDs.TryRemove(order.Id, out outOrder);

                    decimal ignored;
                    _fills.TryRemove(order.Id, out ignored);

                    var clientOrderId = _orderMap.FirstOrDefault(x => x.Value.BrokerId.Contains(brokerId)).Key;
                    if (clientOrderId > 0)
                    {
                        _orderMap.TryRemove(clientOrderId, out outOrder);
                    }
                }

                OnOrderEvent(orderEvent);
            }
            catch (Exception e)
            {
                Log.Error(e);
                throw;
            }
        }
Example #5
0
        protected override async Task HandleResponse(string json, CancellationToken token)
        {
            dynamic msg = null;

            try
            {
                msg = EventResponse.Parse(json) ?? (dynamic)HeartbeatResponse.Parse(json) ?? TradeExecutionUpdate.Parse(json);
            }
            catch (JsonSerializationException)
            {
                await _log.WriteWarningAsync(nameof(HandleResponse), "Unexpected message", json);
            }
            if (msg != null)
            {
                await HandleResponse(msg);

                RechargePingPong();
            }
        }
        private Task MessageHandler(TradeExecutionUpdate tradeUpdate)
        {
            var execution = _bitfinexModelConverter.ToOrderStatusUpdate(tradeUpdate);

            return(_handler.Handle(execution));
        }
Example #7
0
        protected override async Task HandleResponse(string json, CancellationToken token)
        {
            var msg = EventResponse.Parse(json) ?? (dynamic)HeartbeatResponse.Parse(json) ?? TradeExecutionUpdate.Parse(json);

            if (msg != null)
            {
                await HandleResponse(msg);

                RechargePingPong();
            }
        }