/// <summary> /// Process submit order /// For crypto currencies: check if we have the correct amount of base currency, if not, create and additional order for getting the correct base currency amount /// </summary> /// <param name="ticket"></param> /// <returns></returns> protected override OrderTicketResponse SubmitOrder(SubmitOrderTicket ticket) { //Check for associated quant fund var quantfund = Portfolio.QuantFunds.FirstOrDefault(x => x.FundId == ticket.FundId); //Check if we can get the pending order var cashposition = (quantfund == null ? CashManager.GetCashPositions() : CashManager.GetCashPositions(quantfund))[ticket.Security.BaseCurrency]; decimal value = Math.Abs(ticket.Security.ConvertValue(ticket.Quantity * ticket.Security.Price, cashposition.BaseCurrency)); if (cashposition.TotalSettledCash < value) { //We need extra cash for this in currency X decimal valueneeded = value - cashposition.TotalSettledCash; //Create and send var security = Portfolio.BrokerAccount.Securities[$"{cashposition.BaseCurrency}.BC"]; var orderticket = SubmitOrderTicket.MarketOrder(ticket.FundId, security, valueneeded, $"Base currency conversion needed to execute order with id {ticket.OrderId}"); var response = SubmitOrder(orderticket); //Wait for this order if (!response.IsError) { WaitForOrder(response.OrderId); } else { _log.Error($"Could not process currency conversion for order with id {ticket.OrderId}, due to conversion order error {response.ErrorCode} : {response.ErrorMessage}"); } } //Use base implementation return(base.SubmitOrder(ticket)); }
/// <summary> /// Create a new market order ticket /// </summary> /// <param name="security">The security.</param> /// <param name="quantity">The quantity.</param> /// <param name="comment">The comment.</param> /// <param name="exchange"></param> /// <returns></returns> public SubmitOrderTicket MarketOrder(Security security, decimal quantity, string comment = "", string exchange = "") => SubmitOrderTicket.MarketOrder(QuantFund.FundId, security, quantity, comment, exchange);
/// <summary> /// Process any simulated orders /// </summary> /// <param name="datapoints"></param> protected virtual void ProcessSimulatedOrders(IEnumerable <DataPoint> datapoints) { //Check if we need to check this if (OrderCount == 0) { return; } //Only check on tick data and bars var datapointsused = datapoints.Where(x => x.DataType == DataType.QuoteBar || x.DataType == DataType.TradeBar || x.DataType == DataType.Tick); //Triggered orders List <PendingOrder> triggered = new List <PendingOrder>(); //Get all orders that need to be simulated internally foreach (var item in OrderTracker.PendingOrders .Where(x => !x.OrderState.IsDone()) .Where(x => x.IsSimulated) .Join(datapointsused, x => x.Security.Ticker, x => x.Ticker, (po, dp) => new { PendingOrder = po, DataPoint = dp }) .ToArray()) { //Check if already triggered if (triggered.Select(x => x.OrderId).Contains(item.PendingOrder.OrderId)) { continue; } //Get Data var currentprices = item.DataPoint.OrderPrice(item.PendingOrder.Security, item.PendingOrder.Order.Direction); var order = item.PendingOrder.Order; //Create function for converting to a market order SubmitOrderTicket CreateSubmitTicket() => SubmitOrderTicket.MarketOrder(item.PendingOrder.FundId, order.Security, order.Quantity); //logging function void Log(decimal price) => _log.Debug($"Simulated order of type {order.Type} with id {order.InternalId} was triggered at price {price} for processing"); string CreateComment() => $"Sending market order for simulated order {item.PendingOrder.OrderId} and order type {OrderType.Limit}. OldComment: {item.PendingOrder.Comment}"; //Check order type and logic switch (order) { case LimitOrder limitorder: { //Check if limit order price is triggered if (limitorder.IsTriggered(currentprices, out decimal price)) { //create a new order from this order, as it will be converted to a market order Log(price); var norder = CreateSubmitTicket(); norder.Comment = CreateComment(); SubmitOrder(norder); //Add to triggered triggered.Add(item.PendingOrder); } break; } case StopLimitOrder stoplimitorder: { //Check if stop limit order price is triggered if (stoplimitorder.IsTriggered(currentprices, out decimal price)) { //create a new order from this order, as it will be converted to a market order Log(price); var norder = CreateSubmitTicket(); norder.Comment = CreateComment(); SubmitOrder(norder); //Add to triggered triggered.Add(item.PendingOrder); } break; } case StopMarketOrder stoporder: { //Check if stop order price is triggered if (stoporder.IsTriggered(currentprices, out decimal price)) { //create a new order from this order, as it will be converted to a market order Log(price); var norder = CreateSubmitTicket(); norder.Comment = CreateComment(); SubmitOrder(norder); //Add to triggered triggered.Add(item.PendingOrder); } break; } case MarketOnCloseOrder marketOnCloseOrder: { //Check if stop order price is triggered if (marketOnCloseOrder.IsTriggered()) { //create a new order from this order, as it will be converted to a market order var norder = CreateSubmitTicket(); norder.Comment = CreateComment(); SubmitOrder(norder); //Add to triggered triggered.Add(item.PendingOrder); } break; } case MarketOnOpenOrder marketOnOpenOrder: { //Check if stop order price is triggered if (marketOnOpenOrder.IsTriggered()) { //create a new order from this order, as it will be converted to a market order var norder = CreateSubmitTicket(); norder.Comment = CreateComment(); SubmitOrder(norder); //Add to triggered triggered.Add(item.PendingOrder); } break; } default: _log.Error($"Simulated order of type {item.PendingOrder.Order.Type} is not supported, removing order!"); triggered.Add(item.PendingOrder); break; } } //Remove all triggered orders triggered.ForEach(x => OrderTracker.TryRemoveOrder(x.OrderId)); }