// reads position file: qty avgprice holdingssellorderref // gets order and trade book // if holdings sell order is executed, then holding qty is updated to 0, and position file is updated with only today outstanding and empty sellorderref // holdings data is seperate and today outstanding data is seperate // single buy or sell outsanding order at any time is assumed // if there is no sell order for holdings then create a sell order and update position file with holdings and sellorderref // position file contains only the holding data along with the holding sell order ref. it does not have today's outstanding. Only at EOD if conversion to delivery is done then that is assumed to be holding and written to postion file // holding sell order if reqd is placed only once at start in Init, not in loop run. that time iffordeliveryflag is set so that sell price is calculated as per deliverymarkup parameter // in normal run , sell orders are placed as per normal marginmarkup parameter // today's outstanding is derived from the tradebook and outstanding orders derived from order book. no state is saved outside. day before holdings are present in positions file public void Init(AlgoType algoType) { if (!File.Exists(positionFile)) { File.WriteAllText(positionFile, ""); } // just place squareoff orders for previous days open positions pending for delivery - develop it later // Position file always contains the holding qty, holding price and different type of holdings' details (demat/btst, qty, sell order ref) etc ReadPositionFile(); var orders = new Dictionary <string, EquityOrderBookRecord>(); var trades = new Dictionary <string, EquityTradeBookRecord>(); // latest (wrt time) trades or orders appear at start of the output errCode = broker.GetEquityTradeBookToday(false, stockCode, out trades); errCode = broker.GetEquityOrderBookToday(false, true, stockCode, out orders); // get all holding qty trades var holdingTradesRef = holdingsOrders.Select(h => h.OrderRef); // any outstanding qty (buy minus sell trades) today except from holding qty trade todayOutstandingQty = trades.Where(t => !holdingTradesRef.Contains(t.Key)).Sum(t => t.Value.Direction == OrderDirection.SELL ? -t.Value.Quantity : t.Value.Quantity); var buyTrades = trades.Where(t => t.Value.Direction == OrderDirection.BUY); lastBuyPrice = buyTrades.Any() ? buyTrades.First().Value.Price : holdingOutstandingPrice; settlementNumber = buyTrades.Any() ? buyTrades.First().Value.SettlementNumber : ""; var numOutstandingBuyTrades = todayOutstandingQty > 0 ? todayOutstandingQty / ordQty : 0; // these are latest trades taken. each buy trade is for single lot and thus for each lot there is a trade todayOutstandingPrice = numOutstandingBuyTrades == 0 ? 0 : buyTrades.Take(numOutstandingBuyTrades).Average(t => t.Value.Price); ProcessHoldingSellOrderExecution(trades); var buyOrders = orders.Values.Where(o => o.Direction == OrderDirection.BUY && o.Status == OrderStatus.ORDERED); var sellOrders = orders.Values.Where(o => o.Direction == OrderDirection.SELL && o.Status == OrderStatus.ORDERED && !holdingTradesRef.Contains(o.OrderRefenceNumber)); // pick only today's outstanding related sell orders // assumed that there is always at max only single outstanding buy order and a at max single outstanding sell order todayOutstandingBuyOrderRef = buyOrders.Any() ? buyOrders.First().OrderRefenceNumber : ""; todayOutstandingSellOrderRef = sellOrders.Any() ? sellOrders.First().OrderRefenceNumber : ""; var sellOrder = sellOrders.Any() ? sellOrders.First() : null; isFirstBuyOrder = string.IsNullOrEmpty(todayOutstandingBuyOrderRef) && !trades.Where(t => t.Value.Direction == OrderDirection.BUY).Any(); // if sqoff sell order for holdings is needed then place it //assumption is: if there is a holding pending from day before then it would have been converted to delivery if (holdingOutstandingQty > 0) { // get demat and btst listings List <EquityDematHoldingRecord> dematHoldings; errCode = broker.GetDematAllocation(stockCode, out dematHoldings); List <EquityBTSTTradeBookRecord> btstHoldings; errCode = broker.GetBTSTListings(stockCode, out btstHoldings); List <EquityPendingPositionForDelivery> pendingPositions; errCode = broker.GetOpenPositionsPendingForDelivery(stockCode, out pendingPositions); // place sq off sell order, update sell order ref var sellPrice = GetSellPrice(holdingOutstandingPrice, true, false); string sellOrderRef = ""; if (dematHoldings.Any()) { var dematHolding = dematHoldings.First(); if (dematHolding.AvailableQuantity > 0) { errCode = PlaceEquityOrder(stockCode, OrderPositionTypeEnum.Demat, dematHolding.AvailableQuantity, dematHolding.AvailableQuantity, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.DELIVERY, exchange, "", out sellOrderRef); if (errCode == BrokerErrorCode.Success) { holdingsOrders.Add(new HoldingOrder { Type = OrderPositionTypeEnum.Demat, OrderRef = sellOrderRef, Qty = dematHolding.AvailableQuantity, SettlementNumber = "" }); } } } if (btstHoldings.Any()) { foreach (var btstHolding in btstHoldings) { if (btstHolding.AvailableQuantity > 0) { errCode = PlaceEquityOrder(stockCode, OrderPositionTypeEnum.Btst, btstHolding.AvailableQuantity, btstHolding.AvailableQuantity, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.DELIVERY, exchange, btstHolding.SettlementNumber, out sellOrderRef); if (errCode == BrokerErrorCode.Success) { holdingsOrders.Add(new HoldingOrder { Type = OrderPositionTypeEnum.Btst, OrderRef = sellOrderRef, Qty = btstHolding.AvailableQuantity, SettlementNumber = btstHolding.SettlementNumber }); } } } } if (pendingPositions.Any()) { foreach (var pendingPosition in pendingPositions) { if (pendingPosition.AvailableQuantity > 0) { errCode = PlaceEquityOrder(stockCode, OrderPositionTypeEnum.OpenPendingDelivery, pendingPosition.AvailableQuantity, pendingPosition.AvailableQuantity, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.DELIVERY, exchange, pendingPosition.SettlementNumber, out sellOrderRef); if (errCode == BrokerErrorCode.Success) { holdingsOrders.Add(new HoldingOrder { Type = OrderPositionTypeEnum.OpenPendingDelivery, OrderRef = sellOrderRef, Qty = pendingPosition.AvailableQuantity, SettlementNumber = pendingPosition.SettlementNumber }); } } } } UpdatePositionFile(); } // For AverageTheBuyThenSell algo - place sell order for outstanding qty if not already present if (algoType == AlgoType.AverageTheBuyThenSell) { // check if the outstanding sell order has matching qty or not if (sellOrder != null && !string.IsNullOrEmpty(todayOutstandingSellOrderRef) && sellOrder.Quantity < todayOutstandingQty) { // Cancel existing sell order errCode = CancelEquityOrder("[Init Update Sell Qty]", ref todayOutstandingSellOrderRef, EquityOrderType.MARGIN, OrderDirection.SELL); } if (string.IsNullOrEmpty(todayOutstandingSellOrderRef) && todayOutstandingQty > 0) { var sellPrice = GetSellPrice(todayOutstandingPrice, false, false); errCode = PlaceEquityOrder(stockCode, OrderPositionTypeEnum.Margin, todayOutstandingQty, todayOutstandingQty, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.MARGIN, exchange, "", out todayOutstandingSellOrderRef); } } todayBuyOrderCount = buyOrders.Count(); }
// reads position file: qty avgprice holdingssellorderref // gets order and trade book // if holdings sell order is executed, then holding qty is updated to 0, and position file is updated with only today outstanding and empty sellorderref // holdings data is seperate and today outstanding data is seperate // single buy or sell outsanding order at any time is assumed // if there is no sell order for holdings then create a sell order and update position file with holdings and sellorderref // position file contains only the holding data along with the holding sell order ref. it does not have today's outstanding. Only at EOD if conversion to delivery is done then that is assumed to be holding and written to postion file // holding sell order if reqd is placed only once at start in Init, not in loop run. that time iffordeliveryflag is set so that sell price is calculated as per deliverymarkup parameter // in normal run , sell orders are placed as per normal marginmarkup parameter // today's outstanding is derived from the tradebook and outstanding orders derived from order book. no state is saved outside. day before holdings are present in positions file public void Init(AlgoType algoType) { if (!File.Exists(positionFile)) { File.WriteAllText(positionFile, ""); } // Position file always contains the holding qty, holding price and holding sell order ref ReadPositionFile(); var orders = new Dictionary <string, EquityOrderBookRecord>(); var trades = new Dictionary <string, EquityTradeBookRecord>(); // latest (wrt time) trades or orders appear at start of the output errCode = broker.GetEquityTradeBookToday(false, stockCode, out trades); errCode = broker.GetEquityOrderBookToday(false, true, stockCode, out orders); // any outstanding qty (buy minus sell trades) today except from holding qty trade todayOutstandingQty = trades.Where(t => t.Key != holdingSellOrderRef).Sum(t => t.Value.Direction == OrderDirection.SELL ? -t.Value.Quantity : t.Value.Quantity); var buyTrades = trades.Where(t => t.Value.Direction == OrderDirection.BUY); lastBuyPrice = buyTrades.Any() ? buyTrades.First().Value.Price : 0; var numOutstandingBuyTrades = todayOutstandingQty > 0 ? todayOutstandingQty / ordQty : 0; // these are latest trades taken. each buy trade is for single lot and thus for each lot there is a trade todayOutstandingPrice = numOutstandingBuyTrades == 0 ? 0 : buyTrades.Take(numOutstandingBuyTrades).Average(t => t.Value.Price); if (trades.ContainsKey(holdingSellOrderRef)) { ProcessHoldingSellOrderExecution(); } var buyOrders = orders.Values.Where(o => o.Direction == OrderDirection.BUY && o.Status == OrderStatus.ORDERED); var sellOrders = orders.Values.Where(o => o.Direction == OrderDirection.SELL && o.Status == OrderStatus.ORDERED && o.OrderRefenceNumber != holdingSellOrderRef); // pick only today's outstanding related sell orders // assumed that there is always at max only single outstanding buy order and a at max single outstanding sell order todayOutstandingBuyOrderRef = buyOrders.Any() ? buyOrders.First().OrderRefenceNumber : ""; todayOutstandingSellOrderRef = sellOrders.Any() ? sellOrders.First().OrderRefenceNumber : ""; isFirstBuyOrder = string.IsNullOrEmpty(todayOutstandingBuyOrderRef) && !trades.Where(t => t.Value.Direction == OrderDirection.BUY).Any(); // if sqoff sell order for holdings is needed then place it //assumption is: if there is a holding pending from day before then it would have been converted to delivery if (holdingOutstandingQty > 0 && string.IsNullOrEmpty(holdingSellOrderRef)) { // place sq off sell order, update sell order ref var sellPrice = GetSellPrice(holdingOutstandingPrice, true); errCode = PlaceEquityOrder(stockCode, holdingOutstandingQty, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.DELIVERY, exchange, out holdingSellOrderRef); if (errCode == BrokerErrorCode.Success) { UpdatePositionFile(holdingOutstandingQty, holdingOutstandingPrice, holdingSellOrderRef); Trace(string.Format(orderTraceFormat, stockCode, "cash holding squareoff sell", holdingOutstandingQty, sellPrice, "CASH", errCode, OrderPriceType.LIMIT)); } } // For AverageTheBuyThenSell algo - place sell order for outstanding qty if not already present if (algoType == AlgoType.AverageTheBuyThenSell) { if (string.IsNullOrEmpty(todayOutstandingSellOrderRef) && todayOutstandingQty > 0) { var sellPrice = GetSellPrice(todayOutstandingPrice, false); errCode = PlaceEquityOrder(stockCode, todayOutstandingQty, sellPrice.ToString(), OrderPriceType.LIMIT, OrderDirection.SELL, EquityOrderType.MARGIN, exchange, out todayOutstandingSellOrderRef); } } buyOrderCount = buyOrders.Count(); }