// Try min profit squareoff first between 3 - 3.10 time. // From 3.10 to 3.15 time if squareoff of all positions is set to true and the ltp diff meets threshold for max loss pct, then do a market order squareoff public void TrySquareOffNearEOD(AlgoType algoType) { // if after 3 pm, then try to square off in at least no profit no loss if possible. either buy or sell is outstanding if (MarketUtils.IsTimeAfter3()) { var ordPriceType = OrderPriceType.LIMIT; var doUpdateOrders = false; // 3.10 - 3.15 pm time. market order type for forced square off given pct loss is within acceptable range // do it before 3.15, otherwise broker will try to squareoff on its own anytime between 3.15 - 3.30 if (MarketUtils.IsTimeAfter310() && !MarketUtils.IsTimeAfter315() && squareOffAllPositionsAtEOD && !isEODMinLossSquareOffMarketOrderUpdated) { var ltp = GetLTP(); ordPriceType = OrderPriceType.MARKET; var diff = Math.Abs((ltp - todayOutstandingPrice) / ltp); if (diff < pctMaxLossSquareOffPositions && todayOutstandingPrice > goodPrice) { Trace(string.Format("TrySquareOffNearEOD: max loss % {0} is within acceptable range of {1} and avg outstanding price {2} is greater than good price of {3}. Update squareoff at MARKET price type.", diff, pctMaxLossSquareOffPositions, todayOutstandingPrice, goodPrice)); doUpdateOrders = true; isEODMinLossSquareOffMarketOrderUpdated = true; } } // 3 - 3.10 pm time. try simple limit order with min profit price else if (!isEODMinProfitSquareOffLimitOrderUpdated) { Trace(string.Format("TrySquareOffNearEOD: Update squareoff LIMIT order with min profit % price or cancel outstanding orders")); ordPriceType = OrderPriceType.LIMIT; isEODMinProfitSquareOffLimitOrderUpdated = true; doUpdateOrders = true; } if (doUpdateOrders) { if (algoType == AlgoType.AverageTheBuyThenSell) { // just cancel the outstanding buy order if (!string.IsNullOrEmpty(todayOutstandingBuyOrderRef)) { // cancel existing buy order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingBuyOrderRef, OrderDirection.BUY); } // bought qty needs square off. there is outstanding sell order, revise the price to try square off if (!string.IsNullOrEmpty(todayOutstandingSellOrderRef)) { // cancel existing sell order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingSellOrderRef, OrderDirection.SELL); if (errCode == BrokerErrorCode.Success) { todayOutstandingSellOrderRef = ""; // place new sell order, update sell order ref Trace("Placing EOD squareoff updated order"); var sellPrice = GetSellPrice(todayOutstandingPrice, false, true); errCode = PlaceEquityOrder(stockCode, todayOutstandingQty, sellPrice.ToString(), ordPriceType, OrderDirection.SELL, EquityOrderType.MARGIN, exchange, out todayOutstandingSellOrderRef); } } } else if (algoType == AlgoType.SimultaneousBuySell) { // if there is an outstanding order pair, just cancel both if (!string.IsNullOrEmpty(todayOutstandingBuyOrderRef) && !string.IsNullOrEmpty(todayOutstandingSellOrderRef)) { // cancel existing sell order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingSellOrderRef, OrderDirection.SELL); // cancel existing buy order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingBuyOrderRef, OrderDirection.BUY); } // bought qty needs square off. there is outstanding sell order, revise the price to try square off else if (string.IsNullOrEmpty(todayOutstandingBuyOrderRef) && !string.IsNullOrEmpty(todayOutstandingSellOrderRef)) { // cancel existing sell order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingSellOrderRef, OrderDirection.SELL); if (errCode == BrokerErrorCode.Success) { todayOutstandingSellOrderRef = ""; // place new sell order, update sell order ref Trace("Placing EOD squareoff updated order"); var sellPrice = GetSellPrice(todayOutstandingPrice, false, true); errCode = PlaceEquityOrder(stockCode, ordQty, sellPrice.ToString(), ordPriceType, OrderDirection.SELL, EquityOrderType.MARGIN, exchange, out todayOutstandingSellOrderRef); } } // sold qty needs square off. there is outstanding buy order, revise the price to try square off else if (string.IsNullOrEmpty(todayOutstandingSellOrderRef) && !string.IsNullOrEmpty(todayOutstandingBuyOrderRef)) { // cancel existing buy order errCode = CancelEquityOrder("(EOD squareoff) @ " + ordPriceType, ref todayOutstandingBuyOrderRef, OrderDirection.BUY); if (errCode == BrokerErrorCode.Success) { todayOutstandingBuyOrderRef = ""; // place new buy order, update buy order ref Trace("Placing EOD squareoff updated order"); var buyPrice = GetBuySquareOffPrice(todayOutstandingPrice); errCode = PlaceEquityOrder(stockCode, ordQty, buyPrice.ToString(), ordPriceType, OrderDirection.BUY, EquityOrderType.MARGIN, exchange, out todayOutstandingBuyOrderRef); } } } } } }
public void TradeUpdated(object sender, TradeUpdateEventArgs args) { lock (lockRunEitherPlaceBuyOrTradeUpdated) { try { var trade = ConvertTradeUpdateArgsToTradeRecord(args); if (stockCode != trade.StockCode) { return; } var isSellExecutedFully = false; Trace(string.Format(tradeTraceFormat, stockCode, trade.Direction == OrderDirection.BUY ? "bought" : "sold", args.TradedQty, args.TradedPrice, holdingSellOrder.OrderId == trade.OrderId ? "DELIVERY" : "MARGIN", trade.OrderId, trade.TradeId, trade.DateTime, args.ExchTime, args.TimeStamp)); // if any holding sell executed if (trade.OrderId == holdingSellOrder.OrderId) { ProcessHoldingSellOrderExecution(trade.NewQuantity); } // if SELL executed, then update today outstanding with executed qty (handle part executions using NewQuantity) // If it is after 3.15 and broker did auto sq off, then broker's order ref is not with us and wont match with our sq off order. Our sqoff order will be cancelled by the broker if (trade.OrderId == outstandingSellOrder.OrderId || ((MarketUtils.IsTimeAfter315() && trade.EquityOrderType == EquityOrderType.MARGIN && trade.Direction == OrderDirection.SELL))) { if (!string.IsNullOrEmpty(outstandingSellOrder.OrderId) && trade.OrderId != outstandingSellOrder.OrderId) { // If broker initiated market squareoff then Cancel the known sell order to avoid extra execution errCode = CancelEquityOrder("[Broker SquareOff Executed]", ref outstandingSellOrder.OrderId, orderType, OrderDirection.SELL); } todayOutstandingQty -= trade.NewQuantity; if (todayOutstandingQty == 0) { todayOutstandingPrice = 0; outstandingSellOrder.OrderId = ""; todayOutstandingTradeCount = 0; isSellExecutedFully = true; } } // if BUY executed, then place a corresponding updated sell order. if (trade.OrderId == outstandingBuyOrder.OrderId) { currentBuyOrdExecutedQty += trade.NewQuantity; if (currentBuyOrdExecutedQty == currentBuyOrdQty) { Trace(string.Format("[Trade Execution] Fully executed NewQty={0} TotalQty={1}", trade.NewQuantity, currentBuyOrdQty)); outstandingBuyOrder.OrderId = ""; todayOutstandingTradeCount++; } else { Trace(string.Format("[Trade Execution] Partially executed NewQty={0} TotalQty={1}", trade.NewQuantity, currentBuyOrdQty)); } // update outstanding qty and outstanding price to place updated sell order todayOutstandingPrice = (todayOutstandingPrice * todayOutstandingQty) + (trade.NewQuantity * trade.Price); todayOutstandingQty += trade.NewQuantity; todayOutstandingPrice = todayOutstandingQty == 0 ? 0 : todayOutstandingPrice / todayOutstandingQty; UpdatePnLStats(); if (todayOutstandingQty >= maxTodayOutstandingQtyAllowed) { Trace(string.Format("[Trading Limits Hit] TodayOutstandingQty reached the max. todayOutstandingQty: {0} maxTodayPositionValueMultiple: {1}", todayOutstandingQty, maxTodayOutstandingQtyAllowed)); } if ((todayOutstandingQty + holdingOutstandingQty) >= maxTotalOutstandingQtyAllowed) { Trace(string.Format("[Trading Limits Hit] TotalOutstandingQty reached the max. todayOutstandingQty: {0} holdingOutstandingQty: {1} maxTotalPositionValueMultiple: {2}", todayOutstandingQty, holdingOutstandingQty, maxTotalOutstandingQtyAllowed)); } lastBuyPrice = trade.Price; var sellPrice = GetSellPrice(todayOutstandingPrice, false, false); if (!string.IsNullOrEmpty(outstandingSellOrder.OrderId)) { // modify existing sell order if it exists errCode = ModifyEquityOrder("NewBuy modify squareoff", stockCode, outstandingSellOrder.OrderId, OrderPriceType.LIMIT, todayOutstandingQty, sellPrice, out upstoxOrderStatus); // cancel existing sell order if it exists //errCode = CancelEquityOrder("[Buy Executed]", ref outstandingSellOrder.OrderId, orderType, OrderDirection.SELL); } if (string.IsNullOrEmpty(outstandingSellOrder.OrderId)) { // place new sell order if previous cancelled or it was first one, update sell order ref errCode = PlaceEquityOrder(exchStr, stockCode, OrderDirection.SELL, OrderPriceType.LIMIT, todayOutstandingQty, orderType, sellPrice, out outstandingSellOrder.OrderId, out upstoxOrderStatus); } } if (isSellExecutedFully) { // Cancel existing Buy order which might be an average seeking order, as the pricecalc might have changed if (!string.IsNullOrEmpty(outstandingBuyOrder.OrderId)) { // cancel existing buy order errCode = CancelEquityOrder("[Sell Executed Fully]", ref outstandingBuyOrder.OrderId, orderType, OrderDirection.BUY); } } } catch (Exception ex) { Trace("Error:" + ex.Message + "\nStacktrace:" + ex.StackTrace); } } }