예제 #1
0
        /// <summary>
        /// Default market fill model for the base security class. Fills at the last traded price.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="SecurityTransactionModel.StopMarketFill"/>
        /// <seealso cref="SecurityTransactionModel.LimitFill"/>
        public virtual OrderEvent MarketFill(Security asset, MarketOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            if (order.Status == OrderStatus.Canceled) return fill;

            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset)) return fill;

            //Order [fill]price for a market order model is the current security price
            fill.FillPrice = asset.Price;
            fill.Status = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Apply slippage
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    fill.FillPrice += slip;
                    break;
                case OrderDirection.Sell:
                    fill.FillPrice -= slip;
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
예제 #2
0
        private void ClosedOrdersWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            efficiency.closedDeals = (List <MarketOrder>)e.Result;
            if (efficiency.closedDeals == null)
            {
                return;
            }
            var closedDeals = efficiency.closedDeals.ToList();
            // суммарная закрытая сделка
            MarketOrder sumClosed = null;

            if (closedDeals.Count > 0)
            {
                var sumVolume = closedDeals.Sum(d => d.Volume * d.Side);
                sumClosed = new MarketOrder
                {
                    Symbol     = "Сумм",
                    Volume     = Math.Abs(sumVolume),
                    Side       = Math.Sign(sumVolume),
                    ResultDepo = closedDeals.Sum(d => d.ResultDepo),
                    TimeEnter  = closedDeals.Min(d => d.TimeEnter)
                };
                closedDeals.Add(sumClosed);
            }
            closedOrdersFastGrid.DataBind(closedDeals);
            if (sumClosed != null)
            {
                var lastRow = closedOrdersFastGrid.rows.First(r => r.ValueObject == sumClosed);
                lastRow.anchor = FastRow.AnchorPosition.AnchorBottom;
            }

            closedOrdersLoaded = true;
            closedOrdersStandByControl.IsShown = false;
            closedOrdersStandByControl.Hide();
            closedOrdersFastGrid.Show();

            // обновляем статистику
            RebindStatisticsGrid();

            // статистика по валютам
            try
            {
                // ReSharper disable AssignNullToNotNullAttribute
                var blank = new DealCountBySymbol();
                countByTickerChart.Series[0].Points.DataBind(PerformerStatistic.GetDealCountBySymbol(efficiency),
                                                             blank.Property(p => p.Title),
                                                             blank.Property(p => p.DealCount), null);
                // ReSharper restore AssignNullToNotNullAttribute
            }
            catch
            {
            }
            countByTickerStandByControl.IsShown = false;
            countByTickerStandByControl.Hide();
            countByTickerChart.Show();

            // строим диаграмму
            CreateDiagram();

            profitByMonthStandByControl.IsShown = false;
            profitByMonthStandByControl.Hide();
            profitByMonthChart.Show();

            if (ClosedDealsLoaded != null)
            {
                ClosedDealsLoaded(this, new EventArgs());
            }
        }
예제 #3
0
        /// <summary>
        /// Gets all orders not yet closed
        /// </summary>
        /// <returns></returns>
        public override List <Orders.Order> GetOpenOrders()
        {
            var list = new List <Order>();

            try
            {
                var req = new RestRequest("/orders?status=open&status=pending", Method.GET);
                GetAuthenticationToken(req);
                var response = RestClient.Execute(req);

                if (response != null)
                {
                    var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content);
                    foreach (var item in orders)
                    {
                        Order order = null;
                        if (item.Type == "market")
                        {
                            order = new MarketOrder {
                                Price = item.Price
                            };
                        }
                        else if (item.Type == "limit")
                        {
                            order = new LimitOrder {
                                LimitPrice = item.Price
                            };
                        }
                        else if (item.Type == "stop")
                        {
                            order = new StopMarketOrder {
                                StopPrice = item.Price
                            };
                        }
                        else
                        {
                            Log.Error("GDAXBrokerage.GetOpenOrders: Unsupported order type returned from brokerage" + item.Type);
                            continue;
                        }

                        order.Quantity = item.Side == "sell" ? -item.Size : item.Size;
                        order.BrokerId = new List <string> {
                            item.Id.ToString()
                        };
                        order.Symbol = ConvertProductId(item.ProductId);
                        order.Time   = DateTime.UtcNow;
                        order.Status = ConvertOrderStatus(item);
                        order.Price  = item.Price;
                        list.Add(order);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }

            foreach (Order item in list)
            {
                if (item.Status.IsOpen())
                {
                    var cached = this.CachedOrderIDs.Where(c => c.Value.BrokerId.Contains(item.BrokerId.First()));
                    if (cached.Any())
                    {
                        this.CachedOrderIDs[cached.First().Key] = item;
                    }
                }
            }

            return(list);
        }
예제 #4
0
        /// <summary>
        /// Gets all orders not yet closed
        /// </summary>
        /// <returns></returns>
        public override List <Order> GetOpenOrders()
        {
            var endpoint = GetEndpoint("auth/r/orders");
            var request  = new RestRequest(endpoint, Method.POST);

            var parameters = new JsonObject();

            request.AddJsonBody(parameters.ToString());
            SignRequest(request, endpoint, parameters);

            var response = ExecuteRestRequest(request);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception($"BitfinexBrokerage.GetOpenOrders: request failed: [{(int)response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}");
            }

            var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content)
                         .Where(OrderFilter(_algorithm.BrokerageModel.AccountType));

            var list = new List <Order>();

            foreach (var item in orders)
            {
                Order order;
                if (item.Type.Replace("EXCHANGE", "").Trim() == "MARKET")
                {
                    order = new MarketOrder {
                        Price = item.Price
                    };
                }
                else if (item.Type.Replace("EXCHANGE", "").Trim() == "LIMIT")
                {
                    order = new LimitOrder {
                        LimitPrice = item.Price
                    };
                }
                else if (item.Type.Replace("EXCHANGE", "").Trim() == "STOP")
                {
                    order = new StopMarketOrder {
                        StopPrice = item.Price
                    };
                }
                else
                {
                    OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, (int)response.StatusCode,
                                                        "BitfinexBrokerage.GetOpenOrders: Unsupported order type returned from brokerage: " + item.Type));
                    continue;
                }

                order.Quantity = item.Amount;
                order.BrokerId = new List <string> {
                    item.Id.ToStringInvariant()
                };
                order.Symbol = _symbolMapper.GetLeanSymbol(item.Symbol, SecurityType.Crypto, Market.Bitfinex);
                order.Time   = Time.UnixMillisecondTimeStampToDateTime(item.MtsCreate);
                order.Status = ConvertOrderStatus(item);
                order.Price  = item.Price;
                list.Add(order);
            }

            foreach (var item in list)
            {
                if (item.Status.IsOpen())
                {
                    var cached = CachedOrderIDs
                                 .FirstOrDefault(c => c.Value.BrokerId.Contains(item.BrokerId.First()));
                    if (cached.Value != null)
                    {
                        CachedOrderIDs[cached.Key] = item;
                    }
                }
            }

            return(list);
        }
예제 #5
0
        public PyDataType CancelCharOrder(PyInteger orderID, PyInteger regionID, CallInformation call)
        {
            int callerCharacterID = call.Client.EnsureCharacterIsSelected();

            Character character = this.ItemFactory.GetItem <Character>(callerCharacterID);

            using MySqlConnection connection = this.DB.AcquireMarketLock();
            try
            {
                MarketOrder order = this.DB.GetOrderById(connection, orderID);

                if (order.CharacterID != callerCharacterID)
                {
                    throw new MktOrderDidNotMatch();
                }

                long currentTime = DateTime.UtcNow.ToFileTimeUtc();
                // check for timers, no changes in less than 5 minutes
                if (currentTime < order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay])
                {
                    throw new MktOrderDelay((order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) - currentTime);
                }

                // check for escrow
                if (order.Escrow > 0.0 && order.Bid == TransactionType.Buy)
                {
                    using Wallet wallet = this.WalletManager.AcquireWallet(character.ID, 1000);
                    {
                        wallet.CreateJournalRecord(MarketReference.MarketEscrow, null, null, order.Escrow);
                    }
                }

                if (order.Bid == TransactionType.Sell)
                {
                    // create the new item that will be used by the player
                    ItemEntity item = this.ItemFactory.CreateSimpleItem(
                        this.TypeManager[order.TypeID], character.ID, order.LocationID, Flags.Hangar, order.UnitsLeft
                        );
                    // immediately unload it, if it has to be loaded the OnItemUpdate notification will take care of that
                    this.ItemFactory.UnloadItem(item);

                    // check what node this item should be loaded at
                    long stationNode = this.SystemManager.GetNodeStationBelongsTo(order.LocationID);

                    if (stationNode == 0 || this.SystemManager.StationBelongsToUs(order.LocationID) == true)
                    {
                        this.NotificationManager.NotifyCharacter(character.ID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, this.ItemFactory.LocationMarket.ID));
                    }
                    else
                    {
                        this.NotificationManager.NotifyNode(stationNode, OnItemChange.BuildLocationChange(item.ID, this.ItemFactory.LocationMarket.ID, order.LocationID));
                    }
                }

                // finally remove the order
                this.DB.RemoveOrder(connection, order.OrderID);
                // send a OnOwnOrderChange notification
                call.Client.NotifyMultiEvent(new OnOwnOrderChanged(order.TypeID, "Removed"));
            }
            finally
            {
                this.DB.ReleaseMarketLock(connection);
            }

            return(null);
        }
예제 #6
0
 public OrderEvent MarketFill(Security asset, MarketOrder order)
 {
     MarketFillWasCalled = true;
     return(orderEvent);
 }
예제 #7
0
        /// <summary>
        /// Automatically place an order which will set the holdings to between 100% or -100% of *Buying Power*.
        /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM
        /// </summary>
        /// <param name="symbol">   string Symbol indexer</param>
        /// <param name="percentage">decimal fraction of portfolio to set stock</param>
        /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param>
        /// <param name="tag">Tag the order with a short string.</param>
        /// <seealso cref="MarketOrder"/>
        public void SetHoldings(string symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "")
        {
            //Error checks:
            if (!Portfolio.ContainsKey(symbol))
            {
                Error(symbol.ToUpper() + " not found in portfolio. Request this data when initializing the algorithm.");
                return;
            }

            //Range check values:
            if (percentage > 1)
            {
                percentage = 1;
            }
            if (percentage < -1)
            {
                percentage = -1;
            }

            //If they triggered a liquidate
            if (liquidateExistingHoldings)
            {
                foreach (var holdingSymbol in Portfolio.Keys)
                {
                    if (holdingSymbol != symbol && Portfolio[holdingSymbol].AbsoluteQuantity > 0)
                    {
                        //Go through all existing holdings [synchronously], market order the inverse quantity:
                        Order(holdingSymbol, -Portfolio[holdingSymbol].Quantity);
                    }
                }
            }

            var security = Securities[symbol];

            // compute the remaining margin for this security
            var direction = percentage > 0 ? OrderDirection.Buy : OrderDirection.Sell;

            // compute an estimate of the buying power for this security incorporating the implied leverage
            var marginRemaining = Math.Abs(percentage) * security.MarginModel.GetMarginRemaining(Portfolio, security, direction);

            //
            // Since we can't assume anything about the fee structure and the relative size of fees in
            // relation to the order size we need to perform some root finding. In general we'll only need
            // a two loops to compute a correct value. Some exotic fee structures may require more searching.
            //

            // compute the margin required for a single share
            int quantity    = 1;
            var marketOrder = new MarketOrder(symbol, quantity, Time, type: security.Type)
            {
                Price = security.Price
            };
            var marginRequiredForSingleShare = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder);

            // we want marginRequired to end up between this and marginRemaining
            var marginRequiredLowerThreshold = marginRemaining - marginRequiredForSingleShare;

            // iterate until we get a decent estimate, max out at 10 loops.
            int loops          = 0;
            var marginRequired = marginRequiredForSingleShare;

            while (marginRequired > marginRemaining || marginRequired < marginRequiredLowerThreshold)
            {
                var marginPerShare = marginRequired / quantity;
                quantity             = (int)Math.Truncate(marginRemaining / marginPerShare);
                marketOrder.Quantity = quantity;
                marginRequired       = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder);

                // no need to iterate longer than 10
                if (++loops > 10)
                {
                    break;
                }
            }

            // nothing to change
            if (quantity == 0)
            {
                return;
            }

            // adjust for going short
            if (direction == OrderDirection.Sell)
            {
                quantity *= -1;
            }

            MarketOrder(symbol, quantity, false, tag);
        }
예제 #8
0
		public Order SellOrder(Instrument instrument, double qty, string text)
		{
			SingleOrder singleOrder = new MarketOrder(instrument.instrument, Side.Sell, qty, text);
			singleOrder.Strategy = this.strategyName;
			Order order = new Order(singleOrder);
			order.Portfolio = this.portfolio;
			Map.OQ_SQ_Order[order] = singleOrder;
			Map.SQ_OQ_Order[singleOrder] = order;
			return order;
		}
예제 #9
0
        public void GetAllByPortfolioEntry_Returns_Correct_Orders()
        {
            // fixture unique to this test
            var marketOrderRepositoryFixture = new SqlKataMarketOrderRepositoryFixture();

            // arrange
            var marketOrder1 = new MarketOrder(new Decimal(10000.39), 10, new Decimal(1.1), DateTime.Now, true,
                                               PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId);
            var marketOrder2 = new MarketOrder(new Decimal(11000.39), 11, new Decimal(1.2),
                                               DateTime.Now.Subtract(TimeSpan.FromSeconds(3600)), true,
                                               PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId);
            var marketOrder3 = new MarketOrder(new Decimal(12000.39), 12, new Decimal(1.3),
                                               DateTime.Now.Subtract(TimeSpan.FromDays(30)), false,
                                               PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId);

            var marketOrder4 = new MarketOrder(new Decimal(12005.39), 15, new Decimal(12),
                                               DateTime.Now.Subtract(TimeSpan.FromDays(11)), false,
                                               PortfolioEntryId: marketOrderRepositoryFixture.SecondaryPortfolioEntryId);

            var marketOrder5 = new MarketOrder(new Decimal(12006.39), 16, new Decimal(1.5),
                                               DateTime.Now.Subtract(TimeSpan.FromDays(39)), false,
                                               PortfolioEntryId: marketOrderRepositoryFixture.SecondaryPortfolioEntryId);

            // act
            var presumablyEmptyList =
                marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture
                                                                                            .DefaultPortfolioEntryId);
            var presumablyEmptyList2 =
                marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(
                    marketOrderRepositoryFixture.SecondaryPortfolioEntryId);

            marketOrder1 = marketOrder1 with
            {
                Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder1)
            };
            marketOrder2 = marketOrder2 with
            {
                Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder2)
            };
            marketOrder3 = marketOrder3 with
            {
                Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder3)
            };

            marketOrder4 = marketOrder4 with
            {
                Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder4)
            };
            marketOrder5 = marketOrder5 with
            {
                Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder5)
            };

            // assert
            var loadedPortfolios =
                marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture
                                                                                            .DefaultPortfolioEntryId);

            Assert.Empty(presumablyEmptyList);
            Assert.Empty(presumablyEmptyList2);

            Assert.Equal(3, loadedPortfolios.Count);
            Assert.Equal(new List <MarketOrder> {
                marketOrder1, marketOrder2, marketOrder3
            }, loadedPortfolios);

            var loadedPortfoliosSecondary =
                marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture
                                                                                            .SecondaryPortfolioEntryId);

            Assert.Equal(2, loadedPortfoliosSecondary.Count);
            Assert.Equal(new List <MarketOrder> {
                marketOrder4, marketOrder5
            }, loadedPortfoliosSecondary);
        }
        public void DeserializesDecimalizedQuantity()
        {
            var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today);

            TestOrderType(expected);
        }
예제 #11
0
        public void Run(Position initialPosition, Position finalPosition, FeeType feeType, PriceMovement priceMovement, int leverage)
        {
            //Console.WriteLine("----------");
            //Console.WriteLine("PARAMETERS");
            //Console.WriteLine("Initial position: " + initialPosition);
            //Console.WriteLine("Final position: " + finalPosition);
            //Console.WriteLine("Fee type: " + feeType);
            //Console.WriteLine("Price movement: " + priceMovement);
            //Console.WriteLine("Leverage: " + leverage);
            //Console.WriteLine("----------");
            //Console.WriteLine();

            var algorithm = new QCAlgorithm();

            algorithm.SubscriptionManager.SetDataManager(new DataManager());

            var security = algorithm.AddSecurity(_symbol.ID.SecurityType, _symbol.ID.Symbol);

            security.FeeModel = _feeModels[feeType];
            security.SetLeverage(leverage);

            var buyingPowerModel = new TestSecurityMarginModel(leverage);

            security.BuyingPowerModel = buyingPowerModel;

            algorithm.SetCash(Cash);

            Update(security, BasePrice);

            decimal        targetPercentage;
            OrderDirection orderDirection;
            MarketOrder    order;
            decimal        orderFee;
            OrderEvent     fill;
            decimal        orderQuantity;
            decimal        freeMargin;
            decimal        requiredMargin;

            if (initialPosition != Position.Zero)
            {
                targetPercentage = (decimal)initialPosition;
                orderDirection   = initialPosition == Position.Long ? OrderDirection.Buy : OrderDirection.Sell;
                orderQuantity    = algorithm.CalculateOrderQuantity(_symbol, targetPercentage);
                order            = new MarketOrder(_symbol, orderQuantity, DateTime.UtcNow);
                freeMargin       = buyingPowerModel.GetMarginRemaining(algorithm.Portfolio, security, orderDirection);
                requiredMargin   = buyingPowerModel.GetInitialMarginRequiredForOrder(security, order);

                //Console.WriteLine("Current price: " + security.Price);
                //Console.WriteLine("Target percentage: " + targetPercentage);
                //Console.WriteLine("Order direction: " + orderDirection);
                //Console.WriteLine("Order quantity: " + orderQuantity);
                //Console.WriteLine("Free margin: " + freeMargin);
                //Console.WriteLine("Required margin: " + requiredMargin);
                //Console.WriteLine();

                Assert.That(Math.Abs(requiredMargin) <= freeMargin);

                orderFee = security.FeeModel.GetOrderFee(security, order);
                fill     = new OrderEvent(order, DateTime.UtcNow, orderFee)
                {
                    FillPrice = security.Price, FillQuantity = orderQuantity
                };
                algorithm.Portfolio.ProcessFill(fill);

                //Console.WriteLine("Portfolio.Cash: " + algorithm.Portfolio.Cash);
                //Console.WriteLine("Portfolio.TotalPortfolioValue: " + algorithm.Portfolio.TotalPortfolioValue);
                //Console.WriteLine();

                if (priceMovement == PriceMovement.RisingSmall)
                {
                    Update(security, HighPrice);
                }
                else if (priceMovement == PriceMovement.FallingSmall)
                {
                    Update(security, LowPrice);
                }
                else if (priceMovement == PriceMovement.RisingLarge)
                {
                    Update(security, VeryHighPrice);
                }
                else if (priceMovement == PriceMovement.FallingLarge)
                {
                    Update(security, VeryLowPrice);
                }
            }

            targetPercentage = (decimal)finalPosition;
            orderDirection   = finalPosition == Position.Long || (finalPosition == Position.Zero && initialPosition == Position.Short) ? OrderDirection.Buy : OrderDirection.Sell;
            orderQuantity    = algorithm.CalculateOrderQuantity(_symbol, targetPercentage);
            order            = new MarketOrder(_symbol, orderQuantity, DateTime.UtcNow);
            freeMargin       = buyingPowerModel.GetMarginRemaining(algorithm.Portfolio, security, orderDirection);
            requiredMargin   = buyingPowerModel.GetInitialMarginRequiredForOrder(security, order);

            //Console.WriteLine("Current price: " + security.Price);
            //Console.WriteLine("Target percentage: " + targetPercentage);
            //Console.WriteLine("Order direction: " + orderDirection);
            //Console.WriteLine("Order quantity: " + orderQuantity);
            //Console.WriteLine("Free margin: " + freeMargin);
            //Console.WriteLine("Required margin: " + requiredMargin);
            //Console.WriteLine();

            Assert.That(Math.Abs(requiredMargin) <= freeMargin);

            orderFee = security.FeeModel.GetOrderFee(security, order);
            fill     = new OrderEvent(order, DateTime.UtcNow, orderFee)
            {
                FillPrice = security.Price, FillQuantity = orderQuantity
            };
            algorithm.Portfolio.ProcessFill(fill);

            //Console.WriteLine("Portfolio.Cash: " + algorithm.Portfolio.Cash);
            //Console.WriteLine("Portfolio.TotalPortfolioValue: " + algorithm.Portfolio.TotalPortfolioValue);
            //Console.WriteLine();
        }
예제 #12
0
        public static async Task ExampleMain(string[] args)
        {
            // Initialize REST API client.
            var api = new BinanceApi();

            // Check connectivity.
            if (await api.PingAsync())
            {
                Console.WriteLine("Successful!");
            }


            // Create user with API-Key and API-Secret.
            using (var user = new BinanceApiUser("<API-Key>", "<API-Secret>"))
            {
                // Create a client (MARKET) order.
                var order = new MarketOrder(user)
                {
                    Symbol   = Symbol.BTC_USDT,
                    Side     = OrderSide.Buy,
                    Quantity = 0.01m
                };

                try
                {
                    // Send the TEST order.
                    await api.TestPlaceAsync(order);

                    Console.WriteLine("Test Order Successful!");
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Test Order Failed: \"{e.Message}\"");
                }
            }


            // Initialize web socket client (with automatic streaming enabled).
            var webSocketClient = new AggregateTradeWebSocketClient();

            // Handle error events.
            webSocketClient.Error += (s, e) => { Console.WriteLine(e.Exception.Message); };

            // Subscribe callback to BTC/USDT (automatically begin streaming).
            webSocketClient.Subscribe(Symbol.BTC_USDT, evt =>
            {
                var side = evt.Trade.IsBuyerMaker ? "SELL" : "BUY ";

                // Handle aggregate trade events.
                Console.WriteLine($"{evt.Trade.Symbol} {side} {evt.Trade.Quantity} @ {evt.Trade.Price}");
            });

            Console.ReadKey(true); // wait for user input.

            // Unsubscribe from symbol (automatically end streaming).
            webSocketClient.Unsubscribe();


            // Initiatlize web socket cache (with automatic streaming enabled).
            var webSocketCache = new DepthWebSocketCache();

            // Handle error events.
            webSocketCache.Error += (s, e) => { Console.WriteLine(e.Exception.Message); };

            // Subscribe callback to symbol (automatically begin streaming).
            webSocketCache.Subscribe(Symbol.BTC_USDT, evt =>
            {
                // Get symbol from cache (update cache if a symbol is missing).
                var symbol = Symbol.Cache.Get(evt.OrderBook.Symbol);

                var minBidPrice = evt.OrderBook.Bids.Last().Price;
                var maxAskPrice = evt.OrderBook.Asks.Last().Price;

                // Handle order book update events.
                Console.WriteLine($"Bid Quantity: {evt.OrderBook.Depth(minBidPrice)} {symbol.BaseAsset} - " +
                                  $"Ask Quantity: {evt.OrderBook.Depth(maxAskPrice)} {symbol.BaseAsset}");
            });

            Console.ReadKey(true); // wait for user input.

            // Unsubscribe from symbol (automatically end streaming).
            webSocketCache.Unsubscribe();
        }
예제 #13
0
 /// <summary>
 /// Change parameters for market
 /// </summary>
 /// <param name="pos"></param>
 /// <returns></returns>
 protected RequestStatus ModifyMarketOrder(MarketOrder pos)
 {
     return(robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), pos));
 }
예제 #14
0
 /// <summary>
 /// Вызывается на торговых событиях открытие закрытие позиции, срабатывание тейков и стопов
 /// </summary>
 /// <param name="order"></param>
 public virtual void OnTradeEvent(MarketOrder order)
 {
     TerminalLog.Instance.SaveRobotLog(string.Format("робот {0}: срабатывание рыночного ордера {1}, {2}, состояние {3}, side = {4}",
                                                     TypeName, order.ID, order.Symbol, order.State, order.Side));
 }
        /// <summary>
        /// Strategy enter/exit/filtering rules
        /// </summary>
        public override void OnNewBar()
        {
            decimal stopMargin = (decimal)this.GetInputParameter("Trailing Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize;

            int buySignal = (int)this.GetInputParameter("ROCR 100 Buy signal trigger level");

            if (rocr100Indicator.GetROCR100()[1] <= buySignal && rocr100Indicator.GetROCR100()[0] > buySignal && this.GetOpenPosition() == 0)
            {
                // BUY SIGNAL: Entering long and placing a trailing stop loss
                MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position");
                trailingStopOrder = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Trailing stop long exit");

                this.InsertOrder(buyOrder);
                this.InsertOrder(trailingStopOrder);

                // Resetting acceleration and highest close
                acceleration = 0.02m;
                highestClose = Bars.Close[0];
            }
            else if (this.GetOpenPosition() == 1)
            {
                // Checking if the price has moved in our favour
                if (this.Bars.Close[0] > highestClose)
                {
                    highestClose = this.Bars.Close[0];

                    // Increasing acceleration
                    acceleration = acceleration * (highestClose - trailingStopOrder.Price);

                    // Checking if trailing the stop order would exceed the current market price
                    if (trailingStopOrder.Price + acceleration < this.Bars.Close[0])
                    {
                        // Setting the new price for the trailing stop
                        trailingStopOrder.Price = trailingStopOrder.Price + acceleration;
                        this.ModifyOrder(trailingStopOrder);
                    }
                    else
                    {
                        // Cancelling the order and closing the position
                        MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position");

                        this.InsertOrder(exitLongOrder);
                        this.CancelOrder(trailingStopOrder);
                    }
                }
            }
        }
        /// <summary>
        /// Strategy enter/exit/filtering rules
        /// </summary>
        public override void OnNewBar()
        {
            decimal buySignal = (decimal)this.GetInputParameter("Trend-following buy signal");
            decimal sellSignal = (decimal)this.GetInputParameter("Trend-following sell signal");

            decimal stopMargin = (int)this.GetInputParameter("Trailing Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize;
            decimal profitMargin = (int)this.GetInputParameter("Profit Target ticks distance") * this.GetMainChart().Symbol.TickSize;

            bool longTradingEnabled = false;
            bool shortTradingEnabled = false;

            // Day-of-week filter
            if (IsDayEnabledForTrading(this.Bars.Time[0].DayOfWeek))
            {
                // Time-of-day filter
                if (IsTimeEnabledForTrading(this.Bars.Time[0]))
                {
                    // Volatility filter
                    if (CalculateVolatilityRange() > (decimal)this.GetInputParameter("Minimum Range Filter"))
                    {
                        // ADX minimum level and current trending filters
                        if (this.GetOpenPosition() == 0 && IsADXEnabledForLongEntry() && IsBullishUnderlyingTrend())
                        {
                            longTradingEnabled = true;
                        }
                        else if (this.GetOpenPosition() == 0 && IsADXEnabledForShortEntry() && IsBearishUnderlyingTrend())
                        {
                            shortTradingEnabled = true;
                        }
                    }
                }
            }

            if (longTradingEnabled && stochasticIndicator.GetD()[1] <= buySignal && stochasticIndicator.GetD()[0] > buySignal)
            {
                // BUY SIGNAL: Stochastic %D crosses above "buy signal" level
                MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position");
                this.InsertOrder(buyOrder);

                trailingStopOrder = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Catastrophic stop long exit");
                this.InsertOrder(trailingStopOrder);

                profitOrder = new LimitOrder(OrderSide.Sell, 1, this.Bars.Close[0] + profitMargin, "Profit stop long exit");
                this.InsertOrder(profitOrder);

                // Linking Stop and Limit orders: when one is executed, the other is cancelled
                trailingStopOrder.IsChildOf = profitOrder;
                profitOrder.IsChildOf = trailingStopOrder;

                // Setting the initial acceleration for the trailing stop and the furthest (the most extreme) close price
                acceleration = (decimal)this.GetInputParameter("Trailing Stop acceleration");
                furthestClose = this.Bars.Close[0];
            }
            else if (shortTradingEnabled && stochasticIndicator.GetD()[1] >= sellSignal && stochasticIndicator.GetD()[0] < sellSignal)
            {
                // SELL SIGNAL: Stochastic %D crosses below "sell signal" level
                MarketOrder sellOrder = new MarketOrder(OrderSide.Sell, 1, "Enter short position");
                this.InsertOrder(sellOrder);

                trailingStopOrder = new StopOrder(OrderSide.Buy, 1, this.Bars.Close[0] + stopMargin, "Catastrophic stop short exit");
                this.InsertOrder(trailingStopOrder);

                profitOrder = new LimitOrder(OrderSide.Buy, 1, this.Bars.Close[0] - profitMargin, "Profit stop short exit");
                this.InsertOrder(profitOrder);

                // Linking Stop and Limit orders: when one is executed, the other is cancelled
                trailingStopOrder.IsChildOf = profitOrder;
                profitOrder.IsChildOf = trailingStopOrder;

                // Setting the initial acceleration for the trailing stop and the furthest (the most extreme) close price
                acceleration = (decimal)this.GetInputParameter("Trailing Stop acceleration");
                furthestClose = this.Bars.Close[0];
            }
            else if (this.GetOpenPosition() == 1 && this.Bars.Close[0] > furthestClose)
            {
                // We're long and the price has moved in our favour

                furthestClose = this.Bars.Close[0];

                // Increasing acceleration
                acceleration = acceleration * (furthestClose - trailingStopOrder.Price);

                // Checking if trailing the stop order would exceed the current market price
                if (trailingStopOrder.Price + acceleration < this.Bars.Close[0])
                {
                    // Setting the new price for the trailing stop
                    trailingStopOrder.Price = trailingStopOrder.Price + acceleration;
                    trailingStopOrder.Label = "Trailing stop long exit";
                    this.ModifyOrder(trailingStopOrder);
                }
                else
                {
                    // Cancelling the order and closing the position
                    this.CancelOrder(trailingStopOrder);
                    this.CancelOrder(profitOrder);

                    MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position");
                    this.InsertOrder(exitLongOrder);
                }
            }
            else if (this.GetOpenPosition() == -1 && this.Bars.Close[0] < furthestClose)
            {
                // We're short and the price has moved in our favour

                furthestClose = this.Bars.Close[0];

                // Increasing acceleration
                acceleration = acceleration * Math.Abs(trailingStopOrder.Price - furthestClose);

                // Checking if trailing the stop order would exceed the current market price
                if (trailingStopOrder.Price - acceleration > this.Bars.Close[0])
                {
                    // Setting the new price for the trailing stop
                    trailingStopOrder.Price = trailingStopOrder.Price - acceleration;
                    trailingStopOrder.Label = "Trailing stop short exit";
                    this.ModifyOrder(trailingStopOrder);
                }
                else
                {
                    // Cancelling the order and closing the position
                    this.CancelOrder(trailingStopOrder);
                    this.CancelOrder(profitOrder);

                    MarketOrder exitShortOrder = new MarketOrder(OrderSide.Buy, 1, "Exit short position");
                    this.InsertOrder(exitShortOrder);
                }
            }
        }
예제 #17
0
        public void ComputeMarginProperlyAsSecurityPriceFluctuates()
        {
            const decimal leverage       = 1m;
            const int     quantity       = (int)(1000 * leverage);
            var           securities     = new SecurityManager(TimeKeeper);
            var           transactions   = new SecurityTransactionManager(securities);
            var           orderProcessor = new OrderProcessor();

            transactions.SetOrderProcessor(orderProcessor);
            var portfolio = new SecurityPortfolioManager(securities, transactions);

            portfolio.CashBook["USD"].SetAmount(quantity);

            var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL);

            securities.Add(new Security(SecurityExchangeHours, config));
            var security = securities[Symbols.AAPL];

            security.SetLeverage(leverage);

            var           time     = DateTime.Now;
            const decimal buyPrice = 1m;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1));

            var order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            var fill = new OrderEvent(order, DateTime.UtcNow, 0)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            orderProcessor.AddOrder(order);
            var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null);

            request.SetOrderId(0);
            orderProcessor.AddTicket(new OrderTicket(null, request));
            Assert.AreEqual(portfolio.CashBook["USD"].Amount, fill.FillPrice * fill.FillQuantity);

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = buyPrice
            };
            bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder);

            Assert.IsFalse(sufficientCapital);

            // now the stock doubles, so we should have margin remaining

            time = time.AddDays(1);
            const decimal highPrice = buyPrice * 2;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1));

            Assert.AreEqual(quantity, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = highPrice
            };

            sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder);
            Assert.IsTrue(sufficientCapital);

            // now the stock plummets, so we should have negative margin remaining

            time = time.AddDays(1);
            const decimal lowPrice = buyPrice / 2;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, lowPrice, lowPrice, lowPrice, lowPrice, 1));

            Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue);


            // this would not cause a margin call due to leverage = 1
            bool issueMarginCallWarning;
            var  marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning);

            Assert.AreEqual(0, marginCallOrders.Count);

            // now change the leverage and buy more and we'll get a margin call
            security.SetLeverage(leverage * 2);

            order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            fill = new OrderEvent(order, DateTime.UtcNow, 0)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.TotalPortfolioValue);

            marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning);
            Assert.AreNotEqual(0, marginCallOrders.Count);
            Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice
            Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity);
        }
예제 #18
0
 /// <summary>
 /// Default market fill model for the base security class. Fills at the last traded price.
 /// </summary>
 /// <param name="asset">Security asset we're filling</param>
 /// <param name="order">Order packet to model</param>
 /// <returns>Order fill information detailing the average price and quantity filled.</returns>
 /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
 /// <seealso cref="LimitFill(Security, LimitOrder)"/>
 public virtual OrderEvent MarketFill(Security asset, MarketOrder order)
 {
     return(_fillModel.MarketFill(asset, order));
 }
예제 #19
0
        public void MarginComputesProperlyWithMultipleSecurities()
        {
            var securities     = new SecurityManager(TimeKeeper);
            var transactions   = new SecurityTransactionManager(securities);
            var orderProcessor = new OrderProcessor();

            transactions.SetOrderProcessor(orderProcessor);
            var portfolio = new SecurityPortfolioManager(securities, transactions);

            portfolio.CashBook["USD"].SetAmount(1000);
            portfolio.CashBook.Add("EUR", 1000, 1.1m);
            portfolio.CashBook.Add("GBP", -1000, 2.0m);

            var eurCash = portfolio.CashBook["EUR"];
            var gbpCash = portfolio.CashBook["GBP"];
            var usdCash = portfolio.CashBook["USD"];

            var time    = DateTime.Now;
            var config1 = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL);

            securities.Add(new Security(SecurityExchangeHours, config1));
            securities[Symbols.AAPL].SetLeverage(2m);
            securities[Symbols.AAPL].Holdings.SetHoldings(100, 100);
            securities[Symbols.AAPL].SetMarketPrice(new TradeBar {
                Time = time, Value = 100
            });
            //Console.WriteLine("AAPL TMU: " + securities[Symbols.AAPL].MarginModel.GetMaintenanceMargin(securities[Symbols.AAPL]));
            //Console.WriteLine("AAPL Value: " + securities[Symbols.AAPL].Holdings.HoldingsValue);

            //Console.WriteLine();

            var config2 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD);

            securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2));
            securities[Symbols.EURUSD].SetLeverage(100m);
            securities[Symbols.EURUSD].Holdings.SetHoldings(1.1m, 1000);
            securities[Symbols.EURUSD].SetMarketPrice(new TradeBar {
                Time = time, Value = 1.1m
            });
            //Console.WriteLine("EURUSD TMU: " + securities[Symbols.EURUSD].MarginModel.GetMaintenanceMargin(securities[Symbols.EURUSD]));
            //Console.WriteLine("EURUSD Value: " + securities[Symbols.EURUSD].Holdings.HoldingsValue);

            //Console.WriteLine();

            var config3 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURGBP);

            securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3));
            securities[Symbols.EURGBP].SetLeverage(100m);
            securities[Symbols.EURGBP].Holdings.SetHoldings(1m, 1000);
            securities[Symbols.EURGBP].SetMarketPrice(new TradeBar {
                Time = time, Value = 1m
            });
            //Console.WriteLine("EURGBP TMU: " + securities[Symbols.EURGBP].MarginModel.GetMaintenanceMargin(securities[Symbols.EURGBP]));
            //Console.WriteLine("EURGBP Value: " + securities[Symbols.EURGBP].Holdings.HoldingsValue);

            //Console.WriteLine();

            //Console.WriteLine(portfolio.CashBook["USD"]);
            //Console.WriteLine(portfolio.CashBook["EUR"]);
            //Console.WriteLine(portfolio.CashBook["GBP"]);
            //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency);

            //Console.WriteLine();

            //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed);
            //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining);
            //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue);


            var acceptedOrder = new MarketOrder(Symbols.AAPL, 101, DateTime.Now)
            {
                Price = 100
            };

            orderProcessor.AddOrder(acceptedOrder);
            var request = new SubmitOrderRequest(OrderType.Market, acceptedOrder.SecurityType, acceptedOrder.Symbol, acceptedOrder.Quantity, 0, 0, acceptedOrder.Time, null);

            request.SetOrderId(0);
            orderProcessor.AddTicket(new OrderTicket(null, request));
            var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder);

            Assert.IsTrue(sufficientCapital);

            var rejectedOrder = new MarketOrder(Symbols.AAPL, 102, DateTime.Now)
            {
                Price = 100
            };

            sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder);
            Assert.IsFalse(sufficientCapital);
        }
예제 #20
0
        /// <summary>
        /// Calculate the order quantity to achieve target-percent holdings.
        /// </summary>
        /// <param name="symbol">Security object we're asking for</param>
        /// <param name="target">Target percentag holdings, this is an unlevered value, so
        /// if you have 2x leverage and request 100% holdings, it will utilize half of the
        /// available margin</param>
        /// <returns>Order quantity to achieve this percentage</returns>
        public decimal CalculateOrderQuantity(Symbol symbol, decimal target)
        {
            var security = Securities[symbol];
            var price    = security.Price;

            // can't order it if we don't have data
            if (price == 0)
            {
                return(0);
            }

            // if targeting zero, simply return the negative of the quantity
            if (target == 0)
            {
                return(-security.Holdings.Quantity);
            }

            // this is the value in dollars that we want our holdings to have
            var targetPortfolioValue = target * Portfolio.TotalPortfolioValue;
            var currentHoldingsValue = security.Holdings.HoldingsValue;

            // remove directionality, we'll work in the land of absolutes
            var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue);
            var direction        = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell;

            // determine the unit price in terms of the account currency
            var unitPrice = new MarketOrder(symbol, 1, UtcTime).GetValue(security);

            if (unitPrice == 0)
            {
                return(0);
            }

            // calculate the total margin available
            var marginRemaining = Portfolio.GetMarginRemaining(symbol, direction);

            if (marginRemaining <= 0)
            {
                return(0);
            }

            // continue iterating while we do not have enough margin for the order
            decimal marginRequired;
            decimal orderValue;
            decimal orderFees;
            var     feeToPriceRatio = 0;

            // compute the initial order quantity
            decimal orderQuantity = targetOrderValue / unitPrice;

            if (orderQuantity % security.SymbolProperties.LotSize != 0)
            {
                orderQuantity = orderQuantity - (orderQuantity % security.SymbolProperties.LotSize);
            }

            var iterations = 0;

            do
            {
                // decrease the order quantity
                if (iterations > 0)
                {
                    // if fees are high relative to price, we reduce the order quantity faster
                    if (feeToPriceRatio > 0)
                    {
                        orderQuantity -= feeToPriceRatio;
                    }
                    else
                    {
                        orderQuantity--;
                    }
                }

                // generate the order
                var order = new MarketOrder(security.Symbol, orderQuantity, UtcTime);
                orderValue      = order.GetValue(security);
                orderFees       = security.FeeModel.GetOrderFee(security, order);
                feeToPriceRatio = (int)(orderFees / unitPrice);

                // calculate the margin required for the order
                marginRequired = security.MarginModel.GetInitialMarginRequiredForOrder(security, order);

                iterations++;
            } while (orderQuantity > 0 && (marginRequired > marginRemaining || orderValue + orderFees > targetOrderValue));

            //Rounding off Order Quantity to the nearest multiple of Lot Size
            if (orderQuantity % security.SymbolProperties.LotSize != 0)
            {
                orderQuantity = orderQuantity - (orderQuantity % security.SymbolProperties.LotSize);
            }

            // add directionality back in
            return((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity);
        }
        private static DateTime InitializeTest(out BasicTemplateAlgorithm algorithm, out Security security, out PartialMarketFillModel model, out MarketOrder order, out OrderTicket ticket)
        {
            var referenceTimeNY  = new DateTime(2015, 12, 21, 13, 0, 0);
            var referenceTimeUtc = referenceTimeNY.ConvertToUtc(TimeZones.NewYork);

            algorithm = new BasicTemplateAlgorithm();
            algorithm.SetDateTime(referenceTimeUtc);

            var transactionHandler = new BacktestingTransactionHandler();

            transactionHandler.Initialize(algorithm, new BacktestingBrokerage(algorithm), new TestResultHandler(Console.WriteLine));
            Task.Run(() => transactionHandler.Run());

            algorithm.Transactions.SetOrderProcessor(transactionHandler);

            var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);

            security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency));

            model = new PartialMarketFillModel(algorithm.Transactions, 2);

            algorithm.Securities.Add(security);
            algorithm.Securities[Symbols.SPY].FillModel = model;
            security.SetMarketPrice(new Tick {
                Symbol = Symbols.SPY, Value = 100
            });
            algorithm.SetFinishedWarmingUp();

            order = new MarketOrder(Symbols.SPY, 100, referenceTimeUtc)
            {
                Id = 1
            };

            var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, algorithm.UtcTime, null);

            ticket = algorithm.Transactions.ProcessRequest(request);
            return(referenceTimeUtc);
        }
예제 #22
0
 public override OrderEvent MarketFill(Security asset, MarketOrder order)
 {
     MarketFillWasCalled = true;
     return(base.MarketFill(asset, order));
 }
예제 #23
0
        public void ComputeMarginProperlyAsSecurityPriceFluctuates()
        {
            const int quantity     = 1000;
            var       securities   = new SecurityManager();
            var       transactions = new SecurityTransactionManager(securities);
            var       portfolio    = new SecurityPortfolioManager(securities, transactions);

            portfolio.CashBook["USD"].Quantity = quantity;

            var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "AAPL", Resolution.Minute, true, true, true, true, true, 0);

            securities.Add(new Security(config, 1, false));

            var           time     = DateTime.Now;
            const decimal buyPrice = 1m;

            securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", buyPrice, buyPrice, buyPrice, buyPrice, 1));

            var order = new MarketOrder("AAPL", quantity, time)
            {
                Price = buyPrice
            };
            var fill = new OrderEvent(order)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            Assert.AreEqual(portfolio.CashBook["USD"].Quantity, fill.FillPrice * fill.FillQuantity);

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var newOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1))
            {
                Price = buyPrice
            };
            bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder);

            Assert.IsFalse(sufficientCapital);

            // now the stock doubles, so we should have margin remaining

            time = time.AddDays(1);
            const decimal highPrice = buyPrice * 2;

            securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", highPrice, highPrice, highPrice, highPrice, 1));

            Assert.AreEqual(quantity, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var anotherOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1))
            {
                Price = highPrice
            };

            sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder);
            Assert.IsTrue(sufficientCapital);

            // now the stock plummets, so we should have negative margin remaining

            time = time.AddDays(1);
            const decimal lowPrice = buyPrice / 2;

            securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", lowPrice, lowPrice, lowPrice, lowPrice, 1));

            Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue);


            // this would cause a margin call
            var marginCallOrders = portfolio.ScanForMarginCall();

            Assert.AreNotEqual(0, marginCallOrders.Count);
            Assert.AreEqual(-quantity, marginCallOrders[0].Quantity);
            Assert.GreaterOrEqual(-portfolio.MarginRemaining, marginCallOrders[0].Price * marginCallOrders[0].Quantity);
        }
예제 #24
0
        public PyDataType ModifyCharOrder(PyInteger orderID, PyDecimal newPrice, PyInteger bid, PyInteger stationID, PyInteger solarSystemID, PyDecimal price, PyInteger volRemaining, PyInteger issued, CallInformation call)
        {
            int callerCharacterID = call.Client.EnsureCharacterIsSelected();

            Character character = this.ItemFactory.GetItem <Character>(callerCharacterID);

            using MySqlConnection connection = this.DB.AcquireMarketLock();
            try
            {
                MarketOrder order = this.DB.GetOrderById(connection, orderID);

                if (order.CharacterID != callerCharacterID)
                {
                    throw new MktOrderDidNotMatch();
                }

                long currentTime = DateTime.UtcNow.ToFileTimeUtc();
                // check for timers, no changes in less than 5 minutes
                if (currentTime < order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay])
                {
                    throw new MktOrderDelay((order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) - currentTime);
                }

                // ensure the order hasn't been modified since the user saw it on the screen
                if ((int)order.Bid != bid || order.LocationID != stationID || order.Price != price ||
                    order.UnitsLeft != volRemaining || order.Issued != issued)
                {
                    throw new MktOrderDidNotMatch();
                }

                // get the modification broker's fee
                double brokerCost = 0.0;
                double newEscrow  = 0.0;

                this.CalculateBrokerCost(character.GetSkillLevel(Types.BrokerRelations), volRemaining, (newPrice - price), out brokerCost);

                using Wallet wallet = this.WalletManager.AcquireWallet(order.CharacterID, order.AccountID);
                {
                    if (order.Bid == TransactionType.Buy)
                    {
                        // calculate the difference in escrow
                        newEscrow = volRemaining * newPrice;
                        double escrowDiff = order.Escrow - newEscrow;

                        // ensure enough balances
                        wallet.EnsureEnoughBalance(escrowDiff + brokerCost);
                        // take the difference in escrow
                        wallet.CreateJournalRecord(MarketReference.MarketEscrow, null, null, escrowDiff);
                    }
                    else
                    {
                        wallet.EnsureEnoughBalance(brokerCost);
                    }

                    // pay the broker fee once again
                    wallet.CreateJournalRecord(MarketReference.Brokerfee, null, null, -brokerCost);
                }

                // everything looks okay, update the price of the order
                this.DB.UpdatePrice(connection, order.OrderID, newPrice, newEscrow);

                // send a OnOwnOrderChange notification
                call.Client.NotifyMultiEvent(new OnOwnOrderChanged(order.TypeID, "Modified"));
            }
            finally
            {
                this.DB.ReleaseMarketLock(connection);
            }

            return(null);
        }
예제 #25
0
        public void MarginComputesProperlyWithMultipleSecurities()
        {
            var securities   = new SecurityManager();
            var transactions = new SecurityTransactionManager(securities);
            var portfolio    = new SecurityPortfolioManager(securities, transactions);

            portfolio.CashBook["USD"].Quantity = 1000;
            portfolio.CashBook.Add("EUR", 1000, 1.1m);
            portfolio.CashBook.Add("GBP", -1000, 2.0m);

            var eurCash = portfolio.CashBook["EUR"];
            var gbpCash = portfolio.CashBook["GBP"];
            var usdCash = portfolio.CashBook["USD"];

            var time    = DateTime.Now;
            var config1 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "AAPL", Resolution.Minute, true, true, true, true, true, 0);

            securities.Add(new Security(config1, 2, false));
            securities["AAPL"].Holdings.SetHoldings(100, 100);
            securities["AAPL"].SetMarketPrice(time, new TradeBar {
                Time = time, Value = 100
            });
            //Console.WriteLine("AAPL TMU: " + securities["AAPL"].MarginModel.GetMaintenanceMargin(securities["AAPL"]));
            //Console.WriteLine("AAPL Value: " + securities["AAPL"].Holdings.HoldingsValue);

            //Console.WriteLine();

            var config2 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Forex, "EURUSD", Resolution.Minute, true, true, true, true, true, 1);

            securities.Add(new QuantConnect.Securities.Forex.Forex(usdCash, config2, 100, false));
            securities["EURUSD"].Holdings.SetHoldings(1.1m, 1000);
            securities["EURUSD"].SetMarketPrice(time, new TradeBar {
                Time = time, Value = 1.1m
            });
            //Console.WriteLine("EURUSD TMU: " + securities["EURUSD"].MarginModel.GetMaintenanceMargin(securities["EURUSD"]));
            //Console.WriteLine("EURUSD Value: " + securities["EURUSD"].Holdings.HoldingsValue);

            //Console.WriteLine();

            var config3 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Forex, "EURGBP", Resolution.Minute, true, true, true, true, true, 2);

            securities.Add(new QuantConnect.Securities.Forex.Forex(gbpCash, config3, 100, false));
            securities["EURGBP"].Holdings.SetHoldings(1m, 1000);
            securities["EURGBP"].SetMarketPrice(time, new TradeBar {
                Time = time, Value = 1m
            });
            //Console.WriteLine("EURGBP TMU: " + securities["EURGBP"].MarginModel.GetMaintenanceMargin(securities["EURGBP"]));
            //Console.WriteLine("EURGBP Value: " + securities["EURGBP"].Holdings.HoldingsValue);

            //Console.WriteLine();

            //Console.WriteLine(portfolio.CashBook["USD"]);
            //Console.WriteLine(portfolio.CashBook["EUR"]);
            //Console.WriteLine(portfolio.CashBook["GBP"]);
            //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency);

            //Console.WriteLine();

            //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed);
            //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining);
            //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue);


            var acceptedOrder = new MarketOrder("AAPL", 101, DateTime.Now)
            {
                Price = 100
            };
            var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder);

            Assert.IsTrue(sufficientCapital);

            var rejectedOrder = new MarketOrder("AAPL", 102, DateTime.Now)
            {
                Price = 100
            };

            sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder);
            Assert.IsFalse(sufficientCapital);
        }
예제 #26
0
        /// <summary>
        /// Get the maximum market order quantity to obtain a position with a given value in account currency.
        /// Will not take into account buying power.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio, the security and the target percentage holdings</param>
        /// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
        public virtual GetMaximumOrderQuantityForTargetValueResult GetMaximumOrderQuantityForTargetValue(GetMaximumOrderQuantityForTargetValueParameters parameters)
        {
            // adjust target portfolio value to comply with required Free Buying Power Percent
            var targetPortfolioValue =
                parameters.Target * (parameters.Portfolio.TotalPortfolioValue - parameters.Portfolio.TotalPortfolioValue * RequiredFreeBuyingPowerPercent);

            // if targeting zero, simply return the negative of the quantity
            if (targetPortfolioValue == 0)
            {
                return(new GetMaximumOrderQuantityForTargetValueResult(-parameters.Security.Holdings.Quantity, string.Empty, false));
            }

            var currentHoldingsValue = parameters.Security.Holdings.HoldingsValue;

            // remove directionality, we'll work in the land of absolutes
            var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue);
            var direction        = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell;

            // determine the unit price in terms of the account currency
            var unitPrice = new MarketOrder(parameters.Security.Symbol, 1, DateTime.UtcNow).GetValue(parameters.Security);

            if (unitPrice == 0)
            {
                var reason = $"The price of the {parameters.Security.Symbol.Value} security is zero because it does not have any market " +
                             "data yet. When the security price is set this security will be ready for trading.";
                return(new GetMaximumOrderQuantityForTargetValueResult(0, reason));
            }

            // calculate the total margin available
            var marginRemaining = GetMarginRemaining(parameters.Portfolio, parameters.Security, direction);

            if (marginRemaining <= 0)
            {
                var reason = "The portfolio does not have enough margin available.";
                return(new GetMaximumOrderQuantityForTargetValueResult(0, reason));
            }

            // continue iterating while we do not have enough margin for the order
            decimal orderValue = 0;
            decimal orderFees  = 0;
            // compute the initial order quantity
            var orderQuantity = targetOrderValue / unitPrice;

            // rounding off Order Quantity to the nearest multiple of Lot Size
            orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
            if (orderQuantity == 0)
            {
                var reason = $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} " +
                             "and has been rounded to zero.";
                return(new GetMaximumOrderQuantityForTargetValueResult(0, reason, false));
            }

            var loopCount = 0;
            // Just in case...
            var lastOrderQuantity = 0m;

            do
            {
                // Each loop will reduce the order quantity based on the difference between orderValue and targetOrderValue
                if (orderValue > targetOrderValue)
                {
                    var currentOrderValuePerUnit = orderValue / orderQuantity;
                    var amountOfOrdersToRemove   = (orderValue - targetOrderValue) / currentOrderValuePerUnit;
                    if (amountOfOrdersToRemove < parameters.Security.SymbolProperties.LotSize)
                    {
                        // we will always substract at leat 1 LotSize
                        amountOfOrdersToRemove = parameters.Security.SymbolProperties.LotSize;
                    }

                    orderQuantity -= amountOfOrdersToRemove;
                    orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
                }

                if (orderQuantity <= 0)
                {
                    var reason = $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} " +
                                 $"and has been rounded to zero.Target order value {targetOrderValue}. Order fees " +
                                 $"{orderFees}. Order quantity {orderQuantity}.";
                    return(new GetMaximumOrderQuantityForTargetValueResult(0, reason));
                }

                // generate the order
                var order = new MarketOrder(parameters.Security.Symbol, orderQuantity, DateTime.UtcNow);

                var fees = parameters.Security.FeeModel.GetOrderFee(
                    new OrderFeeParameters(parameters.Security,
                                           order,
                                           parameters.Portfolio.CashBook.AccountCurrency)).Value;
                orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount;

                // The TPV, take out the fees(unscaled) => yields available value for trading(less fees)
                // then scale that by the target -- finally remove currentHoldingsValue to get targetOrderValue
                targetOrderValue = Math.Abs(
                    (parameters.Portfolio.TotalPortfolioValue - orderFees - parameters.Portfolio.TotalPortfolioValue * RequiredFreeBuyingPowerPercent)
                    * parameters.Target - currentHoldingsValue
                    );

                // After the first loop we need to recalculate order quantity since now we have fees included
                if (loopCount == 0)
                {
                    // re compute the initial order quantity
                    orderQuantity  = targetOrderValue / unitPrice;
                    orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
                }
                else
                {
                    // Start safe check after first loop
                    if (lastOrderQuantity == orderQuantity)
                    {
                        var message = "GetMaximumOrderQuantityForTargetValue failed to converge to target order value " +
                                      $"{targetOrderValue}. Current order value is {orderValue}. Order quantity {orderQuantity}. " +
                                      $"Lot size is {parameters.Security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol " +
                                      $"{parameters.Security.Symbol}";
                        throw new Exception(message);
                    }

                    lastOrderQuantity = orderQuantity;
                }

                orderValue = orderQuantity * unitPrice;
                loopCount++;
                // we always have to loop at least twice
            }while (loopCount < 2 || orderValue > targetOrderValue);

            // add directionality back in
            return(new GetMaximumOrderQuantityForTargetValueResult((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity));
        }
        /// <summary>
        /// Strategy enter/exit/filtering rules
        /// </summary>
        public override void OnNewBar()
        {
            if (this.GetOpenPosition() == 0)
            {
                int buySignal = (int)this.GetInputParameter("Stochastic %D Buy signal trigger level");

                if (stochasticIndicator.GetD()[1] <= buySignal && stochasticIndicator.GetD()[0] > buySignal)
                {
                    Order buyOrder = new MarketOrder(OrderSide.Buy, 1, "Entry long");
                    limitTakeProfitOrder = new LimitOrder(OrderSide.Sell, 1, Bars.Close[0] + stdDevIndicator.GetStdDev()[0], "Exit long (take profit stop)");

                    this.InsertOrder(buyOrder);
                    this.InsertOrder(limitTakeProfitOrder);
                }
            }
        }
예제 #28
0
        /// <summary>
        /// Gets all orders not yet closed
        /// </summary>
        /// <returns></returns>
        public override List <Order> GetOpenOrders()
        {
            var list = new List <Order>();

            var req = new RestRequest("/orders?status=open&status=pending&status=active", Method.GET);

            GetAuthenticationToken(req);
            var response = ExecuteRestRequest(req, GdaxEndpointType.Private);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception($"GDAXBrokerage.GetOpenOrders: request failed: [{(int) response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}");
            }

            var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content);

            foreach (var item in orders)
            {
                Order order;
                if (item.Type == "market")
                {
                    order = new MarketOrder {
                        Price = item.Price
                    };
                }
                else if (!string.IsNullOrEmpty(item.Stop))
                {
                    order = new StopLimitOrder {
                        StopPrice = item.StopPrice, LimitPrice = item.Price
                    };
                }
                else if (item.Type == "limit")
                {
                    order = new LimitOrder {
                        LimitPrice = item.Price
                    };
                }
                else if (item.Type == "stop")
                {
                    order = new StopMarketOrder {
                        StopPrice = item.Price
                    };
                }
                else
                {
                    OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, (int)response.StatusCode,
                                                        "GDAXBrokerage.GetOpenOrders: Unsupported order type returned from brokerage: " + item.Type));
                    continue;
                }

                order.Quantity = item.Side == "sell" ? -item.Size : item.Size;
                order.BrokerId = new List <string> {
                    item.Id
                };
                order.Symbol = ConvertProductId(item.ProductId);
                order.Time   = DateTime.UtcNow;
                order.Status = ConvertOrderStatus(item);
                order.Price  = item.Price;
                list.Add(order);
            }

            foreach (var item in list)
            {
                if (item.Status.IsOpen())
                {
                    var cached = CachedOrderIDs.Where(c => c.Value.BrokerId.Contains(item.BrokerId.First()));
                    if (cached.Any())
                    {
                        CachedOrderIDs[cached.First().Key] = item;
                    }
                }
            }

            return(list);
        }
예제 #29
0
        /// <summary>
        /// Get the maximum market order quantity to obtain a position with a given buying power percentage.
        /// Will not take into account free buying power.
        /// </summary>
        /// <param name="parameters">An object containing the portfolio, the security and the target signed buying power percentage</param>
        /// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
        public override GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters)
        {
            var targetPortfolioValue = parameters.TargetBuyingPower * parameters.Portfolio.TotalPortfolioValue;

            // no shorting allowed
            if (targetPortfolioValue < 0)
            {
                return(new GetMaximumOrderQuantityResult(0, "The cash model does not allow shorting."));
            }

            var baseCurrency = parameters.Security as IBaseCurrencySymbol;

            if (baseCurrency == null)
            {
                return(new GetMaximumOrderQuantityResult(0, "The security type must be SecurityType.Crypto or SecurityType.Forex."));
            }

            // if target value is zero, return amount of base currency available to sell
            if (targetPortfolioValue == 0)
            {
                return(new GetMaximumOrderQuantityResult(-parameters.Portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount));
            }

            // convert base currency cash to account currency
            var baseCurrencyPosition = parameters.Portfolio.CashBook.ConvertToAccountCurrency(
                parameters.Portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount,
                baseCurrency.BaseCurrencySymbol);

            // remove directionality, we'll work in the land of absolutes
            var targetOrderValue = Math.Abs(targetPortfolioValue - baseCurrencyPosition);
            var direction        = targetPortfolioValue > baseCurrencyPosition ? OrderDirection.Buy : OrderDirection.Sell;

            // determine the unit price in terms of the account currency
            var unitPrice = direction == OrderDirection.Buy ? parameters.Security.AskPrice : parameters.Security.BidPrice;

            unitPrice *= parameters.Security.QuoteCurrency.ConversionRate * parameters.Security.SymbolProperties.ContractMultiplier;

            if (unitPrice == 0)
            {
                if (parameters.Security.QuoteCurrency.ConversionRate == 0)
                {
                    return(new GetMaximumOrderQuantityResult(0, "The internal cash feed required for converting" +
                                                             Invariant($" {parameters.Security.QuoteCurrency.Symbol} to {parameters.Portfolio.CashBook.AccountCurrency} does not") +
                                                             " have any data yet (or market may be closed)."));
                }

                if (parameters.Security.SymbolProperties.ContractMultiplier == 0)
                {
                    return(new GetMaximumOrderQuantityResult(0, $"The contract multiplier for the {parameters.Security.Symbol.Value} security is zero. The symbol properties database may be out of date."));
                }

                // security.Price == 0
                return(new GetMaximumOrderQuantityResult(0, parameters.Security.Symbol.GetZeroPriceMessage()));
            }

            // continue iterating while we do not have enough cash for the order
            decimal orderFees         = 0;
            decimal currentOrderValue = 0;
            // compute the initial order quantity
            var orderQuantity = targetOrderValue / unitPrice;

            // rounding off Order Quantity to the nearest multiple of Lot Size
            orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
            if (orderQuantity == 0)
            {
                string reason = null;
                if (!parameters.SilenceNonErrorReasons)
                {
                    reason = Invariant(
                        $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} and has been rounded to zero."
                        );
                }
                return(new GetMaximumOrderQuantityResult(0, reason, false));
            }

            // Just in case...
            var lastOrderQuantity = 0m;
            var utcTime           = parameters.Security.LocalTime.ConvertToUtc(parameters.Security.Exchange.TimeZone);

            do
            {
                // Each loop will reduce the order quantity based on the difference between
                // (cashRequired + orderFees) and targetOrderValue
                if (currentOrderValue > targetOrderValue)
                {
                    var currentOrderValuePerUnit = currentOrderValue / orderQuantity;
                    var amountOfOrdersToRemove   = (currentOrderValue - targetOrderValue) / currentOrderValuePerUnit;
                    if (amountOfOrdersToRemove < parameters.Security.SymbolProperties.LotSize)
                    {
                        // we will always substract at leat 1 LotSize
                        amountOfOrdersToRemove = parameters.Security.SymbolProperties.LotSize;
                    }
                    orderQuantity -= amountOfOrdersToRemove;
                }

                // rounding off Order Quantity to the nearest multiple of Lot Size
                orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
                if (orderQuantity <= 0)
                {
                    return(new GetMaximumOrderQuantityResult(0,
                                                             Invariant($"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} and has been rounded to zero.") +
                                                             Invariant($"Target order value {targetOrderValue}. Order fees {orderFees}. Order quantity {orderQuantity}.")
                                                             ));
                }

                if (lastOrderQuantity == orderQuantity)
                {
                    throw new ArgumentException(
                              Invariant($"GetMaximumOrderQuantityForTargetValue failed to converge to target order value {targetOrderValue}. ") +
                              Invariant($"Current order value is {currentOrderValue}. Order quantity {orderQuantity}. Lot size is ") +
                              Invariant($"{parameters.Security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol {parameters.Security.Symbol}")
                              );
                }
                lastOrderQuantity = orderQuantity;

                // generate the order
                var order      = new MarketOrder(parameters.Security.Symbol, orderQuantity, utcTime);
                var orderValue = orderQuantity * unitPrice;

                var fees = parameters.Security.FeeModel.GetOrderFee(
                    new OrderFeeParameters(parameters.Security,
                                           order)).Value;
                orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount;

                currentOrderValue = orderValue + orderFees;
            } while (currentOrderValue > targetOrderValue);

            // add directionality back in
            return(new GetMaximumOrderQuantityResult((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity));
        }
예제 #30
0
        private void RenderAccountPositions(StringBuilder sb, int accountId)
        {
            List <MarketOrder> orders;
            var accountInfo = GetAccountInfoFromServer(accountId, out orders);

            if (accountInfo == null)
            {
                return;
            }

            var tradeSignalRequestScript = RenderAjaxSignalDetailQuery(sb);

            // краткая сводка по счету
            sb.AppendLine("      <h3>Счет " + accountId + "</h3>");
            sb.AppendLine("      <p>");
            var ptrVal = new Dictionary <string, string>
            {
                { "Баланс",
                  accountInfo.Equity.ToStringUniformMoneyFormat() + " " + accountInfo.Currency },
                { "Текущая прибыль/убыток",
                  (accountInfo.Equity - accountInfo.Balance).ToStringUniformMoneyFormat() + " " + accountInfo.Currency },
                { "Группа", accountInfo.Group }
            };

            foreach (var pair in ptrVal)
            {
                sb.AppendLine("        " + pair.Key + ": " + pair.Value + "<br/>");
            }
            sb.AppendLine("      </p>");

            // рендерить таблицу открытых позиций
            RenderTableOpenTag(sb);
            RenderTableRowTag(sb, true);
            sb.AppendLine("        <td>№</td><td>Тип</td><td>Объем</td><td>Инстр.</td>" +
                          "<td>Цена</td><td>Время</td><td>Выход</td><td>Результат</td><td>SL</td><td>TP</td><td>Сиг.</td></tr>");

            var evenRow         = false;
            var colorSchemeText = new Dictionary <Cortege2 <bool, bool>, string>
            {
                { new Cortege2 <bool, bool>(true, true), "Black" },   // even - profit
                { new Cortege2 <bool, bool>(false, true), "Black" },  // odd - profit
                { new Cortege2 <bool, bool>(false, false), "Black" }, // odd - loss
                { new Cortege2 <bool, bool>(true, false), "#860000" }  // even - loss
            };
            var colorSchemeBack = new Dictionary <Cortege2 <bool, bool>, string>
            {
                { new Cortege2 <bool, bool>(true, true), "White" },    // even - profit
                { new Cortege2 <bool, bool>(false, true), "#E0E0E0" }, // odd - profit
                { new Cortege2 <bool, bool>(false, false), "FFD6D6" }, // odd - loss
                { new Cortege2 <bool, bool>(true, false), "#White" }  // even - loss
            };

            foreach (var order in orders)
            {
                evenRow = !evenRow;
                var colorText = colorSchemeText[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)];
                var colorBack = colorSchemeBack[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)];

                sb.AppendLine(string.Format("        <tr style=\"color:{0}; background-color:{1}\">",
                                            colorText, colorBack));

                int signalCat, parentDeal;
                var signalString = "";
                if (MarketOrder.GetTradeSignalFromDeal(order, out signalCat, out parentDeal))
                {
                    signalString = string.Format("<a href=\"#\" onclick=\"{0}({1})\">[{1}]</a>",
                                                 tradeSignalRequestScript, signalCat);
                }

                sb.AppendLine(string.Format("        <td>{0}</td><td>{1}</td><td>{2}</td>" +
                                            "<td>{3}</td><td>{4}</td><td>{5:dd.MM.yyyy HH:mm:ss}</td><td>{6}</td><td>{7}</td><td>{8}</td><td>{9}</td><td>{10}</td></tr>",
                                            order.ID, order.Side > 0 ? "BUY" : "SELL", order.Volume.ToStringUniformMoneyFormat(),
                                            order.Symbol, order.PriceEnter.ToStringUniformMoneyFormat(),
                                            order.TimeEnter, (order.PriceExit ?? 0).ToStringUniformPriceFormat(),
                                            order.ResultDepo.ToStringUniformMoneyFormat(),
                                            order.StopLoss.HasValue ? order.StopLoss.Value.ToStringUniformPriceFormat() : " ",
                                            order.TakeProfit.HasValue ? order.TakeProfit.Value.ToStringUniformPriceFormat() : " ",
                                            signalString));
            }
        }
예제 #31
0
        private void MarketDataRoutine(object obj)
        {
            int index = (int)obj;

            while (true)
            {
                if (_isRunning == true && _source != null)
                {
                    if (_source.MarketDataCache.Count > 0)
                    {
                        TDFMarketData[] tmd;
                        if (_source.MarketDataCache.TryDequeue(out tmd))
                        {
                            MarketData[] md = new MarketData[tmd.Length];
                            for (int i = 0; i < tmd.Length; i++)
                            {
                                md[i]           = new MarketData();
                                md[i].WindCode  = tmd[i].WindCode;
                                md[i].Code      = tmd[i].Code;
                                md[i].ActionDay = tmd[i].ActionDay;
                                md[i].Time      = tmd[i].Time;
                                md[i].Status    = tmd[i].Status;
                                md[i].PreClose  = tmd[i].PreClose;
                                md[i].Open      = tmd[i].Open;
                                md[i].High      = tmd[i].High;
                                md[i].Low       = tmd[i].Low;
                                md[i].Match     = tmd[i].Match;
                                for (int j = 0; j < 10; j++)
                                {
                                    md[i].AskPrice[j] = tmd[i].AskPrice[j];
                                    md[i].AskVol[j]   = (int)tmd[i].AskVol[j];
                                    md[i].BidPrice[j] = tmd[i].BidPrice[j];
                                    md[i].BidVol[j]   = (int)tmd[i].BidVol[j];
                                }
                                md[i].NumTrades           = (int)(tmd[i].NumTrades);
                                md[i].Volume              = (int)(tmd[i].Volume);
                                md[i].Turnover            = tmd[i].Turnover;
                                md[i].TotalAskVol         = (int)(tmd[i].TotalAskVol);
                                md[i].TotalBidVol         = (int)(tmd[i].TotalBidVol);
                                md[i].WeightedAvgAskPrice = tmd[i].WeightedAvgAskPrice;
                                md[i].WeightedAvgBidPrice = tmd[i].WeightedAvgBidPrice;
                                md[i].IOPV            = tmd[i].IOPV;
                                md[i].YieldToMaturity = tmd[i].YieldToMaturity;
                                md[i].HighLimited     = tmd[i].HighLimited;
                                md[i].LowLimited      = tmd[i].LowLimited;
                                tmd[i].Prefix.CopyTo(md[i].Prefix, 0);
                                md[i].Syl1 = tmd[i].Syl1;
                                md[i].Syl2 = tmd[i].Syl2;
                                md[i].SD2  = tmd[i].SD2;
                            }
                            lock (this)
                            {
                                _recvDataCount += tmd.Length;
                            }
                            if (NewMarketData != null)
                            {
                                NewMarketData(md);
                            }
                        }
                    }
                    else if (_source.OrderCache.Count > 0)
                    {
                        TDFOrder[] oc;
                        if (_source.OrderCache.TryDequeue(out oc))
                        {
                            MarketOrder[] mo = new MarketOrder[oc.Length];
                            for (int i = 0; i < mo.Length; i++)
                            {
                                mo[i]              = new MarketOrder();
                                mo[i].WindCode     = oc[i].WindCode;
                                mo[i].Code         = oc[i].Code;
                                mo[i].ActionDay    = oc[i].ActionDay;
                                mo[i].Time         = oc[i].Time;
                                mo[i].Order        = oc[i].Order;
                                mo[i].Price        = oc[i].Price;
                                mo[i].Volume       = oc[i].Volume;
                                mo[i].OrderKind    = oc[i].OrderKind;
                                mo[i].FunctionCode = oc[i].FunctionCode;
                            }
                            lock (this)
                            {
                                _recvDataCount += oc.Length;
                            }
                            if (NewMarketOrder != null)
                            {
                                NewMarketOrder(mo);
                            }
                        }
                    }
                    else if (_source.TransactionCache.Count > 0)
                    {
                        TDFTransaction[] t;
                        if (_source.TransactionCache.TryDequeue(out t))
                        {
                            MarketTransaction[] mt = new MarketTransaction[t.Length];
                            for (int i = 0; i < t.Length; i++)
                            {
                                mt[i]              = new MarketTransaction();
                                mt[i].WindCode     = t[i].WindCode;
                                mt[i].Code         = t[i].Code;
                                mt[i].ActionDay    = t[i].ActionDay;
                                mt[i].Time         = t[i].Time;
                                mt[i].Index        = t[i].Index;
                                mt[i].Price        = t[i].Price;
                                mt[i].Volume       = t[i].Volume;
                                mt[i].Turnover     = t[i].Turnover;
                                mt[i].Flag         = t[i].BSFlag;
                                mt[i].OrderKind    = t[i].OrderKind;
                                mt[i].FunctionCode = t[i].FunctionCode;
                                mt[i].AskOrder     = t[i].AskOrder;
                                mt[i].BidOrder     = t[i].BidOrder;
                            }
                            lock (this)
                            {
                                _recvDataCount += t.Length;
                            }
                            if (NewMarketTransction != null)
                            {
                                NewMarketTransction(mt);
                            }
                        }
                    }
                    else if (_source.OrderQueueCache.Count > 0)
                    {
                        TDFOrderQueue[] oq;
                        if (_source.OrderQueueCache.TryDequeue(out oq))
                        {
                            MarketOrderQueue[] moq = new MarketOrderQueue[oq.Length];
                            for (int i = 0; i < oq.Length; i++)
                            {
                                moq[i]           = new MarketOrderQueue();
                                moq[i].WindCode  = oq[i].WindCode;
                                moq[i].Code      = oq[i].Code;
                                moq[i].ActionDay = oq[i].ActionDay;
                                moq[i].Time      = oq[i].Time;
                                moq[i].Side      = oq[i].Side;
                                moq[i].Price     = oq[i].Price;
                                moq[i].Orders    = oq[i].Orders;
                                moq[i].Items     = oq[i].ABItems;
                                oq[i].ABVolume.CopyTo(moq[i].Volume, 0);
                            }
                            lock (this)
                            {
                                _recvDataCount += oq.Length;
                            }
                            if (NewMarketOrderQueue != null)
                            {
                                NewMarketOrderQueue(moq);
                            }
                        }
                    }
                    else
                    {
                        Thread.Sleep(10);
                    }
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }
        /// <summary>
        /// Strategy enter/exit/filtering rules
        /// </summary>
        public override void OnNewBar()
        {
            decimal stopMargin = (int)this.GetInputParameter("Catastrophic Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize;

            int buySignal = (int)this.GetInputParameter("RSI Buy signal trigger level");
            int sellSignal = (int)this.GetInputParameter("RSI Sell signal trigger level");

            if (rsiIndicator.GetRSI()[1] <= buySignal && rsiIndicator.GetRSI()[0] > buySignal && this.GetOpenPosition() != 1)
            {
                if (this.GetOpenPosition() == 0)
                {
                    //BUY SIGNAL: Entering long and placing a catastrophic stop loss
                    MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position");
                    catastrophicStop = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Catastrophic stop long exit");

                    this.InsertOrder(buyOrder);
                    this.InsertOrder(catastrophicStop);
                }
                else if (this.GetOpenPosition() == -1)
                {
                    //BUY SIGNAL: Closing short position and cancelling the catastrophic stop loss order
                    MarketOrder exitShortOrder = new MarketOrder(OrderSide.Buy, 1, "Exit short position (reversal exit signal)");

                    this.InsertOrder(exitShortOrder);
                    this.CancelOrder(catastrophicStop);
                }
            }
            else if (rsiIndicator.GetRSI()[1] >= sellSignal && rsiIndicator.GetRSI()[0] < sellSignal && this.GetOpenPosition() != -1)
            {
                if (this.GetOpenPosition() == 0)
                {
                    //SELL SIGNAL: Entering short and placing a catastrophic stop loss
                    MarketOrder sellOrder = new MarketOrder(OrderSide.Sell, 1, "Enter short position");
                    catastrophicStop = new StopOrder(OrderSide.Buy, 1, this.Bars.Close[0] + stopMargin, "Catastrophic stop short exit");

                    this.InsertOrder(sellOrder);
                    this.InsertOrder(catastrophicStop);
                }
                else if (this.GetOpenPosition() == 1)
                {
                    //SELL SIGNAL: Closing long position and cancelling the catastrophic stop loss order
                    MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position (reversal exit signal)");

                    this.InsertOrder(exitLongOrder);
                    this.CancelOrder(catastrophicStop);
                }
            }
        }
예제 #33
0
        public void GenerateMarginCallOrderTests()
        {
            const int     quantity       = 1000;
            const decimal leverage       = 1m;
            var           orderProcessor = new FakeOrderProcessor();
            var           portfolio      = GetPortfolio(orderProcessor, quantity);

            portfolio.MarginCallModel = new DefaultMarginCallModel(portfolio, null);

            var security = GetSecurity(Symbols.AAPL);

            portfolio.Securities.Add(security);

            var           time     = DateTime.Now;
            const decimal buyPrice = 1m;

            security.SetMarketPrice(new Tick(time, Symbols.AAPL, buyPrice, buyPrice));

            var order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            var fill = new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            orderProcessor.AddOrder(order);
            var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null);

            request.SetOrderId(0);
            orderProcessor.AddTicket(new OrderTicket(null, request));
            Assert.AreEqual(portfolio.Cash, fill.FillPrice * fill.FillQuantity);

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = buyPrice
            };
            var hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, newOrder).IsSufficient;

            Assert.IsFalse(hasSufficientBuyingPower);

            // now the stock doubles, so we should have margin remaining
            time = time.AddDays(1);
            const decimal highPrice = buyPrice * 2;

            security.SetMarketPrice(new Tick(time, Symbols.AAPL, highPrice, highPrice));
            portfolio.InvalidateTotalPortfolioValue();

            Assert.AreEqual(quantity, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = highPrice
            };

            hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, anotherOrder).IsSufficient;
            Assert.IsTrue(hasSufficientBuyingPower);

            // now the stock plummets, so we should have negative margin remaining
            time = time.AddDays(1);
            const decimal lowPrice = buyPrice / 2;

            security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice));
            portfolio.InvalidateTotalPortfolioValue();

            Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue);

            // this would not cause a margin call due to leverage = 1
            bool issueMarginCallWarning;
            var  marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning);

            Assert.IsFalse(issueMarginCallWarning);
            Assert.AreEqual(0, marginCallOrders.Count);

            // now change the leverage to test margin call warning and margin call logic
            security.SetLeverage(leverage * 2);

            // Stock price increase by minimum variation
            const decimal newPrice = lowPrice + 0.01m;

            security.SetMarketPrice(new Tick(time, Symbols.AAPL, newPrice, newPrice));
            portfolio.InvalidateTotalPortfolioValue();

            // this would not cause a margin call, only a margin call warning
            marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning);
            Assert.IsTrue(issueMarginCallWarning);
            Assert.AreEqual(0, marginCallOrders.Count);

            // Price drops again to previous low, margin call orders will be issued
            security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice));
            portfolio.InvalidateTotalPortfolioValue();

            order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            fill = new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };
            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.TotalPortfolioValue);

            marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning);
            Assert.IsTrue(issueMarginCallWarning);
            Assert.AreEqual(1, marginCallOrders.Count);
        }
예제 #34
0
		public Order MarketOrder(OrderSide side, double qty, string text)
		{
			SingleOrder singleOrder;
			if (side == OrderSide.Buy)
			{
				singleOrder = new MarketOrder(this.sq_Instrument, Side.Buy, qty, text);
			}
			else
			{
				singleOrder = new MarketOrder(this.sq_Instrument, Side.Sell, qty, text);
			}
			singleOrder.Strategy = this.strategyName;
			Order order = new Order(singleOrder);
			order.Portfolio = this.portfolio;
			Map.OQ_SQ_Order[order] = singleOrder;
			Map.SQ_OQ_Order[singleOrder] = order;
			return order;
		}
예제 #35
0
        /// <summary>
        /// Converts the specified Oanda order into a qc order.
        /// The 'task' will have a value if we needed to issue a rest call for the stop price, otherwise it will be null
        /// </summary>
        private Order ConvertOrder(DataType.Order order)
        {
            Order qcOrder;

            switch (order.type)
            {
            case "limit":
                qcOrder = new LimitOrder();
                if (order.side == "buy")
                {
                    ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound);
                }

                if (order.side == "sell")
                {
                    ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound);
                }

                break;

            case "stop":
                qcOrder = new StopLimitOrder();
                if (order.side == "buy")
                {
                    ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound);
                }

                if (order.side == "sell")
                {
                    ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound);
                }
                break;

            case "marketIfTouched":
                //when market reaches the price sell at market.
                qcOrder = new StopMarketOrder {
                    Price = Convert.ToDecimal(order.price), StopPrice = Convert.ToDecimal(order.price)
                };
                break;

            case "market":
                qcOrder = new MarketOrder();
                break;

            default:
                throw new NotSupportedException("The Oanda order type " + order.type + " is not supported.");
            }
            var securityType = _symbolMapper.GetBrokerageSecurityType(order.instrument);

            qcOrder.Symbol   = _symbolMapper.GetLeanSymbol(order.instrument, securityType, Market.Oanda);
            qcOrder.Quantity = ConvertQuantity(order);
            qcOrder.Status   = OrderStatus.None;
            qcOrder.BrokerId.Add(order.id.ToString());
            var orderByBrokerageId = _orderProvider.GetOrderByBrokerageId(order.id);

            if (orderByBrokerageId != null)
            {
                qcOrder.Id = orderByBrokerageId.Id;
            }
            qcOrder.Duration      = OrderDuration.Custom;
            qcOrder.DurationValue = XmlConvert.ToDateTime(order.expiry, XmlDateTimeSerializationMode.Utc);
            qcOrder.Time          = XmlConvert.ToDateTime(order.time, XmlDateTimeSerializationMode.Utc);

            return(qcOrder);
        }
예제 #36
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            var events = new List <string>();

            if (tickers.Length == 0 || isHistoryStartOff)
            {
                return(events);
            }

            if (lastTrade == null)
            {
                lastTrade = new ThreadSafeTimeStamp();
                lastTrade.Touch();
            }

            // секунд с последнего трейда...
            var timeSince = (DateTime.Now - lastTrade.GetLastHit()).TotalSeconds;

            if (timeSince < tradeIntervalSec)
            {
                return(events);
            }

            lastTrade.Touch();

            // затребовать все сделки со своим magic
            List <MarketOrder> orders;

            GetMarketOrders(out orders, true);
            var sides = tickers.ToDictionary(t => t, t => 1);

            if (orders != null)
            {
                foreach (var order in orders)
                {
                    if (sides.ContainsKey(order.Symbol))
                    {
                        sides[order.Symbol] = -order.Side;
                    }
                    // закрыть старую сделку
                    CloseMarketOrder(order.ID);
                }
            }

            // открыть новые сделки
            foreach (var tickerSide in sides)
            {
                var newOrd = new MarketOrder
                {
                    Symbol        = tickerSide.Key,
                    Side          = tickerSide.Value,
                    AccountID     = robotContext.AccountInfo.ID,
                    Magic         = Magic,
                    Volume        = FixedVolume,
                    ExpertComment = "SimpleTradeMachine"
                };
                var rst = robotContext.SendNewOrderRequest(protectedContext.MakeProtectedContext(),
                                                           RequestUniqueId.Next(), newOrd, OrderType.Market, 0, 0);
            }

            return(events);
        }
예제 #37
0
        public IncomingMessage Visit(Mantle.Fix44.MarketDataIncrementalRefresh msg)
        {
            var res = new IncomingMessage();

            res.SendingTime = msg.StandardHeader.SendingTime.Value;
            if (!msg.StandardHeader.SendingTime.HasValue)
            {
                _log.Warn("MarketDataResponse is missing SendingTime field: {0}", msg);
                return(null);
            }
            res.MarketData.Value.ServerTime = msg.StandardHeader.SendingTime.Value;
            if (!msg.Instrument.Symbol.HasValue)
            {
                _log.Warn("MarketDataResponse is missing Symbol field: {0}", msg);
                return(null);
            }
            res.MarketData.Value.Symbol = msg.Instrument.Symbol.Value;
            foreach (Mantle.Fix44.MDEntry entry in msg.MDEntries)
            {
                string      error;
                MarketOrder order = MakeOrder(entry, out error);
                if (order != null)
                {
                    var diff = new MarketOrderDiff();
                    diff.Order = order;
                    if (!entry.MDUpdateAction.HasValue)
                    {
                        _log.Warn("Missing MDUpdateAction field: {0}", msg);
                        break;
                    }
                    else if (entry.MDUpdateAction.Value == '0')
                    {
                        diff.Type = DiffType.New;
                    }
                    else if (entry.MDUpdateAction.Value == '1')
                    {
                        diff.Type = DiffType.Change;
                    }
                    else if (entry.MDUpdateAction.Value == '2')
                    {
                        diff.Type = DiffType.Delete;
                    }
                    else
                    {
                        _log.Warn("Invalid value of MDUpdateAction {0}: {1}", entry.MDUpdateAction.Value, msg);
                        break;
                    }
                    if (res.MarketData.Value.Diff == null)
                    {
                        res.MarketData.Value.Diff = new List <MarketOrderDiff>();
                    }
                    res.MarketData.Value.Diff.Add(diff);
                    continue;
                }
                if (error != null)
                {
                    _log.Warn("{0}: {1}", error, msg);
                    continue;
                }
                _log.Warn("Ignoring MDEntry of unkonwn format: {0}", msg);
            }
            return(res);
        }